最近はLAMBDA関数を使った数式の解説をよく書いています。これからのExcelでは、VBAよりも関数を使った数式が重要になると感じていますし、何よりも、個人的に楽しいです。そうしたコンテンツが多いのは、単純に私の趣味みたいなものなので、どうかご容赦くださいな。そんな折、先日のセミナーで、また「田中さん、最近LAMBDA関数のコンテンツ多いですよね」みたいな話題になり、続けて「なんか難しいんですけど、そもそもLAMBDA関数って何ですか?」って聞かれました。う~む、これだけLAMBDA関数のコンテンツを書いてきましたけど、そう言えば、あらためて"LAMBDA関数とは何か"って書いていませんでしたね。なので基本に立ち返って、今回はLAMBDA関数について易しく解説します。
結論から書くと、LAMBDA関数とは「新しい関数を作る関数」です。Excelには昔から、たくさんの関数が用意されています。合計を求めるSUM関数や、平均を計算してくれるAVERAGE関数などなど、現在のExcelには500を超える数の関数が実装されています。しかし、当たり前ですけど、それらはすべて、Microsoftが設計して作成した関数です。必ずしも、すべてのExcelユーザーが満足するはずもなく、関数の動作や仕様に対して「こういうとき、こうなればいいのに」みたいな望みを抱くことも少なくありません。でも、しかたありません。われわれExcelユーザーは、Microsoftが作った仕組みを使うしかないです。だって、私たちが自由に関数を作ることは、できなかったのですから[*1(下記参照)]。そこに登場したのがLAMBDA関数です。LAMBDA関数を使うと、好きな動作を持つ、自分専用の関数を作ることができます。LAMBDA関数とは「新しい関数を作る関数」なんです。(大事なことなので2回書きました)
LAMBDA関数の"LAMBDA(ラムダ)"という関数名に疑問を抱く方も多いでしょう。だいたいの関数は、その名前を見れば、何をする関数なのかが何となく分かります。しかし"LAMBDA(ラムダ)"って言われてもピンときませんよね。
"LAMBDA"はギリシャ語です。「アルファ(α), ベータ(β), ガンマ(γ)…」と続く11番目の文字「Λ(大文字)」「λ(小文字)」です。この"LAMBDA(ラムダ)"という単語は、いろいろな場面で使われています[*2(下記参照)]。
上図の上から2つめに表示されているように、コンピュータ(プログラミング)の世界でも昔から用いられています。一般的には「ラムダ計算」とか「ラムダ式」のように使われ、プログラミング言語によって違いはありますが、大雑把かつ乱暴に括れば「独自の関数を作って活用しよう」みたいな仕組みです。そうしたネーミングからも、ExcelのLAMBDA関数が「関数を作る関数」だと分かります。
「いやいや、そんな変な関数なんか使わなくたって、普通に独自の計算やってるし」って感じる方もいるでしょう。Excelで一般的に使われる"数式"と"関数"は、ちょっと違います。
たとえば「セルA1の値を2倍して1を加える」という計算を考えてみましょう。参照式で書くと「2*A1+1」ですね。このとき、計算の元となるセルはA1固定です。対して関数は、任意の"入力(引数)"を受け取って、決まった計算を行い、結果を"出力"するというパッケージです。両者の違いは微妙ですし、一般的なExcelユーザーであれば、厳密に理解(区別)する必要はないでしょう。強いて言うなら「関数は数式の一部」みたいなものです。たとえば「=SUM(A1:A3)*2」という数式は、数式の中でSUM関数がパーツとして使われています。
LAMBDA関数は関数を作る関数です。作られるのが関数であるのなら、その関数に、何らかの方法で引数を渡さなければなりません。LAMBDA関数に引数を渡すには、いくつかの方法があります。まず、LAMBDA関数の使い方は大きく2つに分かれます。「LAMBDA関数に名前を定義して、セル内でその名前を使う」方法と「セルに直接LAMBDA関数を入力する」方法です。
実際にやってみましょう。ここでは、次のような処理をします。
引数として受け取った数値が「1だったら"田中"」「2だったら"小原"」「3だったら"佐倉"」「それ以外だったら"--"」を返します。これには、いろいろな関数を使えますが、今回はXLOOKUP関数でいきます。「それ以外だったら」エラーになるので、エラーのときの引数を指定できて便利だからです。数式は、次のようになりますね。
LAMBDA(n,XLOOKUP(n,{1,2,3},{"田中","小原","佐倉"},"--"))
数式で使用している「n」が引数です。この数式に名前を定義します。Ctrl + Alt + [F3]を押して[新しい名前]ダイアログボックスを開きます。
定義する名前は「GETNAME」としました。参照範囲ボックスに「=LAMBDA(n,XLOOKUP(n,{1,2,3},{"田中","小原","佐倉"},"--"))」と入力して[OK]ボタンをクリックします。
準備完了です。新しく名前定義した「GETNAME」をセル内で使ってみましょう。
"GET"まで入力すると、関数オートコンプリートリストにも表示されています。
関数ヒントには「nという1つの引数を指定する」旨が表示されます。
引数として、セルA1を指定しました。
セルB1のセルを、4行目までコピーすると、正しく処理されていることが分かります。
名前定義を使わないで、LAMBDA関数をセルに直接入力することも可能です。
さて、引数はどうやって指定すればいいのでしょう。難しく考える必要はありません。何かの関数を入力するとき「=関数名(引数)」のように書きますよね。今回は、LAMBDA関数の部分が新しい関数なのですから、LAMBDA関数の後ろに括弧をつけて引数を指定すればLAMBDA関数に引数を渡せます。つまり「=LAMBDA(…)(引数)」みたいな感じですね。
できました。できましたけど、これ、意味なくないですか?この程度だったら、直接XLOOKUP関数を入力しちゃえばいいですよね。
そう、このやり方は(少なくとも今回のケースでは)、あまり意味がありません。そうではなく、セルに直接LAMBDA関数を入力して、そのLAMBDA関数に引数を渡すには、もうひとつ別な方法があります。それは「(LAMBDA関数の)ヘルパー関数」を使うやり方です。
ヘルパー関数とは、ザックリ言うと「LAMBDA関数に引数を渡せる」関数たちのことです[*3(下記参照)]。2025年7月現在、MAKEARRAY関数, MAP関数, BYROW関数, BYCOL関数, SCAN関数, REDUCE関数, ISOMITTED関数が用意されています。
たとえば、次のような感じです。
MAP関数は、MAP関数の引数に指定したモノ(今回はA1:A4)を、「A1→A2→A3→A4」のように1つずつLAMBDA関数の引数に渡します。LAMBDA関数は、受け取った引数を元にして処理を行います。
このように、セルに直接LAMBDA関数を入力するときは、一般的にヘルパー関数と一緒に使うことが多いです。ヘルパー関数は、それぞれ便利な仕組みを持っていますので、組み合わせることで、かなり複雑な処理も実現できたりします。
名前定義する方法と、直接入力する方法ですが、双方にメリットとデメリットがあります。まず、名前定義する方から考えてみましょう。
何と言ってもメリットは、セル内に記述する数式が短くなることです。どんなに長い数式で複雑な処理をしていても、短い名前を定義しておけば、それで呼び出せるのですから、効果は絶大です。また、一度名前を定義しておけば、いろいろなセルで、新しい関数のように使えますし、名前定義をコピーすれば別のブックでも活用できます。反面のデメリットは、可読性が劣化することです。「これは何の処理をしているんだろう?」とセル内の数式を見ても、ただ「=GETNAME(A1)」としか表示されません。何も知らないようなビギナーだったら、まず間違いなく「Excelには、自分の知らないGETNAME関数があるんだ!」って誤解して、きっとネットで検索するでしょうね。本稿で解説したLAMBDA関数の仕組みを理解している方なら「ん?名前定義かな?」って気づくかも知れませんけど、そもそも名前定義という機能を知らないExcelユーザーもいます。よしんば名前定義に行き着いたとしても、そこに登録されている複雑な数式を読み解かなければなりません。あと、最近のExcelには「この数式を説明してください」という機能が追加されました。
「=GATNAME(A1)」のように名前定義を使った数式で実行すると、次のような回答が返されます。
この数式 =GETNAME(A1) は、セルA1の値(この場合は「1」)を引数として、GETNAMEという関数に渡しています。
• GETNAMEはExcel標準の関数ではなく、ユーザー定義関数(UDF)やアドインによるカスタム関数である可能性が高いです。
• 一般的に「GETNAME」という名前から推測すると、A1の値や参照に関連する「名前」や「ラベル」を取得する目的で作成された関数かもしれません。
• このシートではA1に「1」が入力されており、B1にこの数式が入力されています。
• 実際にどのような値が返るかは、GETNAME関数の定義内容によります。
要約:
=GETNAME(A1)は、A1の値(1)を使って、GETNAMEというカスタム関数で何らかの「名前」情報を取得しようとしています。関数の具体的な動作は、VBAやアドインの実装内容次第です。
どんな処理をしているかを知りたいのに、まったく役に立ちませんね。てゆーか、上記の解説には「ユーザー定義関数」「カスタム関数」「VBA」「アドイン」というキーワードが書かれているので、ビギナーだったら、おそらくそれらを疑ったり調べたりするのでは?「名前定義」という言葉が書かれていないので、たぶん誤誘導されてしまうと思いますよ。
では、セルに直接入力する方はどうでしょう。メリットは、名前定義という機能を知らなくても、処理のすべてがセル内に表示されることです。また、上記の「この数式を説明してください」では、次のような回答になります。
この数式 =MAP(A1:A4,LAMBDA(a,XLOOKUP(a,{1,2,3},{"田中","小原","佐倉"},"--"))) は、A1:A4の各値を日本語の名前に変換し、該当しない場合は「-–」を返します。
• MAP関数でA1:A4(1, 2, 3, 4)の各値を順番に処理します。
• 各値aに対して、XLOOKUP関数でaが1なら「田中」、2なら「小原」、3なら「佐倉」を返します。
• 1, 2, 3以外(例: 4)は「-–」を返します。
• 結果としてB1:B4には「田中」「小原」「佐倉」「–-」が表示されます。
こちらの方が助かりますよね。「この数式を説明してください」は、多くのExcelユーザーが泣いて喜び庭駆け回る新機能です。絶対に、使えた方がいいでしょ。対するデメリットは、数式が複雑になる点ですかね。LAMBDA関数を使うと、かなり高度な処理も可能です。当然、その数式は長くなります。「この数式を説明してください」が使えないExcelでは、読み解くのが困難なケースもあるでしょう。たとえば下図は「縦横で構成されたデータを、リスト形式に"逆ピボット"する」数式です。
まぁ、これは極端な例ですが、この長い数式を読み解くのって…無理ゲーですし、いきなりこんな難解な数式が表示されたら心臓に悪いです。 ちなみに「この数式を説明してください」の回答は次のとおりです。
この数式 =LET(A,Data17[名前],B,Data17[#見出し], C,COUNTA(DROP(B,,1)),D,TOCOL(DROP(B,,1)),E,DROP(Data17,,1), X,DROP(REDUCE("",A,LAMBDA(a,b,VSTACK(a,EXPAND(b,C,,b)))),1), Y,DROP(REDUCE("",SEQUENCE(C+1),LAMBDA(a,b,VSTACK(a,D))),1), VSTACK({"名前","属性","値"},HSTACK(X,Y,TOCOL(DROP(Data17,,1))))) は、テーブル「Data17」のデータを「逆ピボット(アンピボット)」し、各「名前」と「属性(A/B/C)」の組み合わせごとに「値」を持つ縦長の表(F1:H13)を作成します。
主な処理の流れ:
• A,Data17[名前]:元テーブルの「名前」列(例:田中、小原、佐倉、花澤)を取得。
• B,Data17[#見出し]:元テーブルのヘッダー(「名前」「A」「B」「C」)を取得。
• C,COUNTA(DROP(B,,1)):属性列(A/B/C)の数をカウント。
• D,TOCOL(DROP(B,,1)):属性名(A/B/C)を縦方向の配列に変換。
• E,DROP(Data17,,1):元テーブルから「名前」列を除いた値部分(A/B/C列の値)を取得。
• X,DROP(REDUCE("",A,LAMBDA(a,b,VSTACK(a,EXPAND(b,C,,b)))),1):各「名前」を属性数分繰り返して縦方向に並べる(例:田中×3, 小原×3, …)。
• Y,DROP(REDUCE("",SEQUENCE(C+1),LAMBDA(a,b,VSTACK(a,D))),1):属性名(A/B/C)を各「名前」ごとに繰り返して縦方向に並べる。
• TOCOL(DROP(Data17,,1)):値部分(A/B/C列の値)を縦方向に並べる。
• VSTACK({"名前","属性","値"},HSTACK(X,Y,TOCOL(DROP(Data17,,1)))):ヘッダー行(「名前」「属性」「値」)を付けて、3列(名前・属性・値)の縦長表にまとめる。
この結果、元の横持ちテーブル(Data17)を、各「名前」と「属性」の組み合わせごとに「値」を持つ縦持ちテーブル(F1:H13)へ変換します。
上述した「メリットとデメリット」のように、LAMBDA関数を使った数式は、いずれにしても読み解くのが難しいです。個人的な感想としては、実務ではあまり多用しない方が良いのではないかと思います。実務では、何よりも"引き継ぎやすさ"や"可読性"が重要です。腕自慢のような、複雑で難解な数式を使うと、よく言われる「マクロの属人化問題」と同じことになります。実務でLAMBDA関数を使うときは、十分に留意してください。
補足
(*1)昔から、似たような仕組みはありました。たとえば、数式に名前をつけて、独自関数のように使う方法です。これは、引数に決まった位置関係のセルを指定しなければならず、お世辞にも使い勝手が良いとは言えませんでした。さらに、VBAを使えば"ユーザー定義関数"を作ることも可能です。Functionプロシージャをセル内の数式として使うやり方です。これは今でも普通に使えますし、私の自作アドインにも、2つくらい仕込んでいます。
(*2)正直、私が"ラムダ"と聞いて、真っ先に思い浮かぶのは、草刈正雄が刑事ドラマで乗っていた「ギャランラムダΛ」ですねw 本当は、田中邦衛が乗ってた「ランサー・セレステ」の方が好きでしたけど。いやぁ、あの頃のドラマは本当におもしろかった。今では、コンプライアンスの関係で、絶対に作れないでしょうけど。なんつたって、街中で普通に拳銃ぶっ放しますからねw
数年前ですが、急に脳内で「浮かれ飛ぶ街にムーンライト~俺の心に夢を投げる~やるせないぜGive me love tonight…」の曲が無限ループしまして。勢いで「プロハンター」のDVDをポチりました。いやぁ、最高っすわ。クリエーションの竹田和夫も懐かしい。「プロハンター」に主演されていた藤竜也さんですが、実は一度だけスカッシュのお相手をしてもらったことがあります。20代だった当時、まだほとんど知られていなかったスカッシュにハマっていて(マイラケット今でも持ってます)。コーチをしてくれていた女性(全日本3位?2位だっけ?)のホームコートへ見学に行ったら藤竜也さんがいらして。恥ずかしながらお相手していただきました。ドラマの数倍格好よかったなぁ。バイト代を貯めて、藤竜也さんがよく着ていた赤いスウィングトップをVANで買いましたっけ(バラクーダのG9は予算的に無理だった)。以上、年寄りの"昔話"でした。
(*3)厳密に言うと、引数を渡せるのはLAMBDA関数だけではありません。文法的に間違っていなければ、ほかの関数にも引数を渡せます。たとえば
みたいに。まぁ、上図だったらヘルパー関数を使う意味もありませんけど、LAMBDA関数以外も使えるという例です。BYROW関数とAND関数を組み合わせると、行単位での比較が簡単に書けるのですが、それはまた別の機会に。