「あの商品、何行目だっけ?」を毎回手で探していませんか?
在庫管理表に100種類の商品が並んでいる。スケジュール表の中から特定の担当者名を探したい。そんなとき、目視でスクロールして探していませんか?
1列に並んだデータならMATCH関数一発で終わります。ところが行と列が交差した2次元の表になった瞬間、話は一気にややこしくなります。
この記事では、Excel 365で使えるモダンな関数(MAP・TOCOL・IF・ADDRESS)を組み合わせて、2次元配列の中から特定の値が存在するセルアドレスを取得する方法を、コピペで使えるレベルまで丁寧に解説します。
⚠️ 動作環境について:この記事で紹介する
MAP・TOCOL関数はExcel 365専用です。Excel 2019以前やGoogleスプレッドシートでは動作しません。従来環境向けの方法は後述の「古典的な方法」を参照してください。
サンプルデータの準備
以下のような果物の管理表(A1:C3)を例として使います。範囲を変えるだけでどんな大きさの表にも応用できます。
| A列 | B列 | C列 | |
|---|---|---|---|
| 1行 | りんご | みかん | ぶどう |
| 2行 | バナナ | いちご | メロン |
| 3行 | キウイ | もも | マンゴー |
目標:「いちご」が入っているセル(B2)のアドレス$B$2を数式で取得する。
従来の方法とその限界
まず比較のために、古くから使われてきたADDRESS+MATCH+INDEXの組み合わせを見てみましょう。
=ADDRESS(
MATCH("いちご", INDEX(A1:C3, 0, MATCH("いちご", A1:C3, 0)), 0) + ROW(A1) - 1,
MATCH("いちご", A1:C3, 0)
)
この方法には、次のような実用上の問題があります。
- 表の位置がズレると壊れる:行や列を挿入・削除するとMATCHの基準がズレてエラーになる
- 複数一致に対応できない:同じ値が複数セルにあると最初の1件しか取れない
- 数式の意図が読みにくい:後でメンテナンスするときに何をしているかわかりにくい
このような背景から、Excel 365のラムダ系関数を使ったモダンなアプローチが有効です。
モダンな方法:MAP+IF+ADDRESS+TOCOLの組み合わせ
ステップ1:MAPで各セルにアドレスを割り当てる
MAP関数は、配列の各要素に対して処理を適用できるラムダ系関数です。まず、各セルのアドレスを一覧にしてみましょう。
=MAP(A1:C3, LAMBDA(cell, ADDRESS(ROW(cell), COLUMN(cell))))
出力される2次元配列:
"$A$1" "$B$1" "$C$1" "$A$2" "$B$2" "$C$2" "$A$3" "$B$3" "$C$3"
ROW(cell)でその要素の行番号、COLUMN(cell)で列番号を取得し、ADDRESSでアドレス文字列に変換しています。
ステップ2:IFで条件に一致するアドレスだけを残す
次に、「いちご」が入っているセルだけアドレスを返し、それ以外は空文字にします。
=MAP(A1:C3, LAMBDA(cell, IF(cell="いちご", ADDRESS(ROW(cell), COLUMN(cell)), "")))
出力のイメージ:
"" "" "" "" "$B$2" "" "" "" ""
ステップ3:TOCOLで1列にまとめて空白を除去する
2次元のまま返ってきた配列を、TOCOLで1列に変換します。第2引数に1を指定することで空白セルを除外できます(0は全て保持、2はエラーのみ除外、1は空白を除外)。
=TOCOL( MAP(A1:C3, LAMBDA(cell, IF(cell="いちご", ADDRESS(ROW(cell), COLUMN(cell)), ""))), 1 )
結果:$B$2
たったこれだけで目的のアドレスが取得できます。
実用化:検索値をセル参照で可変にする
数式に値をハードコーディングするより、セルから参照できると便利です。E1セルに検索したい値を入力する形にしましょう。
=TOCOL( MAP(A1:C3, LAMBDA(cell, IF(cell=E1, ADDRESS(ROW(cell), COLUMN(cell)), ""))), 1 )
E1に「もも」と入力すれば$B$3、「メロン」なら$C$2とリアルタイムで結果が変わります。表の範囲A1:C3を変更するだけで、100行×20列の大きな表にもそのまま使えます。
応用:行番号・列番号・列名を個別に取得する
アドレス文字列ではなく数値や列名で欲しい場合もあります。
行番号を数値で取得する
=TOCOL(MAP(A1:C3, LAMBDA(cell, IF(cell=E1, ROW(cell), ""))), 1)
列番号を数値で取得する
=TOCOL(MAP(A1:C3, LAMBDA(cell, IF(cell=E1, COLUMN(cell), ""))), 1)
列名(アルファベット)を取得する ※少し上級
=TOCOL( MAP(A1:C3, LAMBDA(cell, IF(cell=E1, SUBSTITUTE(ADDRESS(1, COLUMN(cell), 4), "1", ""), ""))), 1 )
ADDRESS(1, COLUMN(cell), 4)は相対参照形式で"B1"のような文字列を返します。SUBSTITUTEで"1"を除去することで列名だけを取り出しています。ネストが深くなるため、まずはアドレス取得に慣れてから試してみてください。
複数箇所に同じ値がある場合
同じ値が表内に複数存在する場合、TOCOLはすべての一致アドレスを縦方向に並べて返します。
$B$2 $C$3 ("いちご"が2か所にある場合)
最初の1件だけ取得したい場合は、外側にINDEXを追加します。
=INDEX(
TOCOL(
MAP(A1:C3, LAMBDA(cell, IF(cell=E1, ADDRESS(ROW(cell), COLUMN(cell)), ""))),
1
),
1
)
まとめ:この記事で学んだことを持ち帰ろう
| 関数 | 役割 |
|---|---|
MAP |
2次元配列の各セルに処理を適用する |
IF |
条件に一致するセルだけを選別する |
ADDRESS |
行・列番号からセルアドレス文字列を生成する |
ROW / COLUMN |
セルの行番号・列番号を取得する |
TOCOL |
2次元配列を1列に変換し、空白を除去する |
この記事を読んだあなたが今日からできること:
MAP+IF+ADDRESS+TOCOLの基本形をコピーして自分の表に貼り付ける- 検索値をセル参照(E1など)にして再利用しやすくする
- 複数一致の場合は
INDEX(..., 1)で先頭を取り出す
従来のINDEX+MATCHよりも数式の意図が読みやすく、表の変更にも強いのがこの方法の最大のメリットです。業務の表に当てはめて、ぜひ試してみてください。
次回のLookupシリーズでは、複数条件での2次元検索について解説予定です。お楽しみに!