1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Excelで「関数型脳」を作る Vol.4:VBAのループが無くても大丈夫 —— フィルターして、行(レコード)で回す(FILTER / MAP / BYROW)

1
Last updated at Posted at 2026-02-28

前回、Excelで「関数型脳」を作る Vol.3:関数を生み出す工場 —— クロージャと部分適用で、「関数を生成する工場」を作り、_標準計算_軽減計算 という、設定済みの専用関数を作りました。

Vol.4では、テーブルの各レコードに対して、このような関数を適用する話しになります。

ありがちですが、次のようなユースケースを想定して話を進めます。

  • テーブルから異常値を取り除き、
  • OKのレコードに対して関数を適用する

VBAなら、For i = 1 To ... とでも書いて、IF文でOKレコードに対して関数を適用すればよいですが、Excelの数式(LAMBDA)の中には繰り返し構文がないので、どうしたものかなぁと。


1. OKデータの抽出:FILTER関数

例えば、手元に1,000行の「売上明細」があるとして、

  • 「在庫が1以上、かつ東京都のデータだけ」を計算したい。

VBAなら If 文で判定しながらループしますが、関数型脳では FILTER関数 でまず「計算対象」を確定させます。

=LET(
    _テーブル, A2:D1000,
    // 1. まずは「面」で絞り込む(AND条件は * で繋ぐ)
    _条件_数量あり, INDEX(_テーブル, , 3) > 0,
    _条件_東京都, INDEX(_テーブル, , 4) = "東京都",
    _計算対象, FILTER(_テーブル, _条件_数量あり * _条件_東京都),

2. 配列の各行に対して自前の関数を適用させる:MAP関数

絞り込んだレコードに対して、「単価 × 数量」関数を適用します。
これに MAP関数 を使います。MAP関数は、複数の列(配列)を同時に受け取り、関数を適用してくれます。

    _商品名, INDEX(_計算対象, , 1),
    _単価列, INDEX(_計算対象, , 2),
    _数量列, INDEX(_計算対象, , 3),
    // 2つの配列を渡すと、LAMBDAも引数を2つ受け取れます
    _売上合計, MAP(_単価列, _数量列, LAMBDA(_単価, _数量, _単価 * _数量)),
    _売上合計
)

image.png

「A列とB列を、1行ずつペアにして計算」しています。
これでもよいのですが、頭の中のイメージと実装が離れているので、しっくりこないです。

頭の中はテーブルをイメージしていますし、 レコード毎に関数を適用していく イメージで組み立てたいです。


3. 「行(レコード)」という塊で扱う:BYROW関数

例えば、「税区分が A なら標準、B なら軽減」といった具合に、行の中にある複数の値を見て判断する ことがよくあります。
MAP で引数を増やし続けるよりも、BYROW関数 を使って「行そのもの」を LAMBDA に渡す方が、頭の中のイメージにマッチします。

ここで、Vol.3 の「関数工場」とBYROWを使ってみます。

=LET(
    // --- Vol.3の工場(クロージャ) ---
    _税込計算工場, LAMBDA(_税率, LAMBDA(_価格, _価格 * (1 + _税率))),
    _標準計算, _税込計算工場(0.1),
    _軽減計算, _税込計算工場(0.08),

    _データ, A2:C100, // [商品名, 単価, 税区分("通常" or "軽減")]
    
    // 1. FILTERでノイズを除去
    _対象, FILTER(_データ, INDEX(_データ,,2) > 0),

    // 2. BYROWで「行(レコード)」として回す
    _結果, BYROW(_対象, LAMBDA(_行,
        LET(
            _価格, INDEX(_行, 2),
            _税区分, INDEX(_行, 3),
            // 行の中身を見て、工場で作った「専用関数」を使い分ける
            IF(_税区分 = "通常", _標準計算(_価格), _軽減計算(_価格))
        )
    )),

    _結果
)

あらかじめ作っておいた標準税率と軽減税率の関数を、税区分を使ってテーブルの各レコードに関数を適用して計算しています。
image.png


4. MAPやBYROWってレコードを返せないの?!

ここまでの書き方だと1列だけの結果を返しているのですが、結果をレコードで返したくなります。で、試しに次のような関数を書きました。

=MAP(
    SEQUENCE(5),
    LAMBDA(x, HSTACK(x, x * 2))
)

これを実行すると、 #CALC! というエラーになります。MAPBYROWは、次のような入れ子になっている配列は返せません。

{{1,2};{2,4};{3,6};{4,8};{5,10}}

うーん。あらたな問題発生。Excelだとだめなのか?!


5. まとめ

VBAの For ループがなくても、だいぶやりたいことがやれるようになってきました。

  • FILTER: テーブルから処理対象レコードを抽出して、サブセットのテーブルを作る。
  • MAP: 複数の列を並列に同期させて関数を適用する。
  • BYROW: 行を「レコード」という塊で捉えて関数を適用する。

とここまでは良かったのですが、「配列のネスト」をどうするか?という新たな課題が出てきました...と思いましたが、Vol.2の関数も値として扱える考え方に従えば、問題は解けそうです。

次回は、配列の壁を破壊し、すべてのデータを一点に収束させ、あるいは自在に再構築する。
Excelで「関数型脳」を作る Vol.5:REDUCE(畳み込み)と THUNK —— 世界を一つにまとめ上げる
です。


今日の気づき

  • MAP は便利だが、複雑な条件分岐が出てくると BYROW で「レコード」として扱いたくなる。
  • Vol.3で作った「専用関数」を BYROW の中で使うと、数式が「ロジック(文章)」として読めるようになる。
  • BYROW の中で HSTACK などを使って「配列」を返そうとすると #CALC! エラーになるが、関数も値として扱えると考えれば問題は解けそう。
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?