はじめに:Excelで「ウォーリー」を探せ?
突然ですが、以下の数字の羅列を見てください。
{4,62,53,21...}

この広大な数字の海(A1:J10)の中から、以下の「2×2の正方形の並び」がどこにあるか、一瞬で見つけられますか?
{11,15;7,22}

「11の右隣が15」で、かつ「11の真下が7」で、「15の真下が22」である場所…。
まるで「ウォーリーをさがせ!」のようなパターンマッチングを、Excelの数式で行うのが今回のミッションです。

実務でこれができると?
「こんなパズル、仕事で使うの?」と思うかもしれません。
しかし、この「2次元のパターン認識」の考え方は、以下のような場面で応用が効きます。
- 座席表の管理: 「縦横2席ずつ空いているスペース(4人席)」を一瞬で探し出す。
- 倉庫の棚卸し: 特定の商品群(A商品の隣にB商品がある配置など)のミスを見つける。
- 画像のピクセル解析: Excel方眼紙で描いたドット絵から、特定の色パターン(目の形など)を抽出する。これなんて最高に面白い遊びですよね!
- シフト表のチェック: 「先輩・後輩」のペアが、2日連続で同じ配置になっている箇所を探す。
今回は、この難問を解くための数式を、最新のExcel 2024、Microsoft 365から、なんとWindows 95時代のExcel 97でも動く数式まで、歴史を遡りながら紹介します。
本記事では、無料のWeb版Excelを使用して検証および画像の作成を行っています。Windowsはもちろん、MacやLinuxの方もブラウザさえあれば挑戦できます!
ミッションの準備
まずは、検索対象となるデータ(A1:J10)を用意します。
以下の配列をシートに入力してください。
={4,62,53,21,74,68,49,65,30,26;2,79,53,92,48,58,7,7,1,51;50,60,47,71,47,11,15,25,12,87;5,17,90,12,83,7,22,96,15,4;86,19,11,15,75,8,48,57,43,9;29,2,7,22,36,67,46,90,36,60;42,48,35,37,60,40,7,64,57,15;62,34,94,86,41,25,29,85,64,44;61,50,29,98,69,52,69,15,9,10;14,53,36,2,87,21,7,24,34,3}
探すターゲット(検索値)はこれです。
左上:11、右上:15
左下:7、右下:22
該当するセル範囲の左上のセル番号を返すことが今回のゴールです。
答えは F3(F3:G4の範囲)とC5(C5:D6の範囲)になります。
これを数式で導き出しましょう!
また、今回は見やすさ重視のため、$F$3,$C$5などの$マーク表記ではなく、単にF3,C5のようにスッキリと表示させます。
最新鋭の武器で挑む(Excel 2024 / 365)
関数の詳細な仕様については、Microsoft公式のヘルプも参考にしてください。
はじめに、最新の動的配列数式(スピル)を使ったスマートな解法を紹介します。
数式1:NA関数とTOCOLで座標を抽出
=ADDRESS(
TOCOL(
IF(
(A1:I9=11)*(B1:J9=15)*(A2:I10=7)*(B2:J10=22),
ROW(A1:I9),
NA()
),
2
),
TOCOL(
IF(
(A1:I9=11)*(B1:J9=15)*(A2:I10=7)*(B2:J10=22),
COLUMN(A1:I9),
NA()
),
2
),
4
)【難易度:★★★☆☆】【実用度:★★★★☆】
【ロジックの解説】
1.条件判定 (A1:I9=11)*(B1:J9=15)*(A2:I10=7)*(B2:J10=22)
4つの条件(左上が11、右隣が15…)を掛け算(AND条件)で判定します。すべて満たす場所だけが TRUE(1) になります。

※範囲を A1:I9(10列目と10行目は右・下が無いため検索対象外)にしているのがポイントです。
2.IF(..., ROW(...), NA())
条件を満たす場合は「行番号」を、満たさない場合は「#N/Aエラー」を返します。
ここで ""(空白)ではなく、あえて NA() を使うのは、次の工程のためです。

""(空白)だと次のTOCOLでうまく無視できない場合があります。
3.TOCOL(..., 2)
配列を縦一列に並べ直します。第2引数に 「2」 を指定することで、「エラー値を無視して詰める」 ことができます。

これで、正解の行番号(3)(5)が抽出されます。(列番号も同様に行います)

4.ADDRESS(行, 列, 4)
抽出した行と列を使って、セル番地(F3)(C5)という文字を作成します。

数式2:TEXTSPLITで一撃解決
次に、座標をバラバラに計算せず、一度文字にしてから分解する方法です。
=TEXTSPLIT(
TEXTJOIN(
",",
1,
IF(
(A1:I9=11)*(B1:J9=15)*(A2:I10=7)*(B2:J10=22),
ADDRESS(ROW(A1:I9),COLUMN(A1:I9),4),
""
)
),
,
","
)【難易度:★★★★☆】【実用度:★★★☆☆】
【ロジックの解説】
1. IF(...) で条件を満たす場所の「セル番地(F3,C5)」を作ります。それ以外は空白 "" にします。

2. TEXTJOIN(",", 1, ...) で、それらをカンマ区切りで連結します。第2引数の「1」で空白を無視するため、正解のセル番地だけが残ります。

3. TEXTSPLIT でカンマで区切って、再び配列に戻してスピルさせます。

数式3:文字列連結で検索(超シンプル)
続いて、「4つのセルを比較する」のではなく、「4つのセルをくっつけて、1つのキーワードとして探す」という発想です。
Excel初心者の方にはこれが一番わかりやすいかもしれません。
=FILTER(
TOCOL(ADDRESS(ROW(A1:I9),COLUMN(A1:I9),4)),
TOCOL(A1:I9&"_"&B1:J9&"_"&A2:I10&"_"&B2:J10="11_15_7_22")
)【難易度:★★☆☆☆】【実用度:★★★★★】
【ロジックの解説】
1. A1:I9&"_"&B1:J9&"_"&A2:I10&"_"&B2:J10
上下左右の4つのセルをアンダーバーで繋いで、一つの文字列を作ります。

2. TOCOL(...="11_15_7_22")
それが正解のキーワードと一致するか判定し、縦一列のTRUE/FALSEリストを作ります。

3. FILTER
その条件を使って、全セル番地リストの中から正解の場所だけを抜き出します。

FILTER関数が使用できない場合、以下の記事をご覧ください。
数式4:MAP関数でマニアックに(365限定)
さらに、LAMBDA関数を使ったプログラミング的なアプローチです。
=LET(
s, SEQUENCE(100),
r, QUOTIENT(s-1,10)+1,
c, MOD(s-1,10)+1,
h, MAP(r, c, LAMBDA(x, y,
AND(IFERROR(INDEX(A1:J10, x+{0,0,1,1}, y+{0,1,0,1})={11,15,7,22}, 0))
)),
ADDRESS(FILTER(r, h), FILTER(c, h), 4)
)【難易度:★★★★★】【実用度:★★☆☆☆】
【ロジックの解説】
1. SEQUENCE(100) で1~100の連番を作り、QUOTIENT(商)とMOD(余り)を使って、10×10のグリッドの全座標(r, c)を生成します。商と余りを使うことで、重複のないユニークな座標を作り出せます。


2. MAP と LAMBDA を使い、全ての座標(x, y)に対して総当たりチェックを行います。
3. INDEX(..., x+{0,0,1,1}, y+{0,1,0,1})
ここが美しいポイント!基準点x,yに対して配列定数を足すことで、「自分、右、下、右下」の4つの値を一気に取得し、{11,15,7,22} と比較しています。


4. FILTER
正解の場所だけを抜き出します。


【重要】Excel 2007以降での挑戦と「失敗例」
ここからはスピル機能がない時代の戦い方です。
ここで多くの人が陥る「致命的な罠」を紹介します。
【注意】
ここから紹介する数式は、スピルしないため、結果が複数ある場合は数式を下方向(行方向)にコピーして使用してください。
数式5:【失敗例】IFERRORとSMALLの落とし穴
「条件に合う行番号の最小値」と「列番号の最小値」を取ればいいのでは?と思いますよね。
=IFERROR(ADDRESS(
SMALL(IF(($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),ROW($A$1:$I$9)),ROW(A1)),
SMALL(IF(($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),COLUMN($A$1:$I$9)),ROW(A1)),
4),"")【難易度:★★☆☆☆】【実用度:★☆☆☆☆】
この数式、正解が1つなら正しく動きます。
しかし、もし正解が複数あった場合(F3とC5にある場合)、とんでもないことが起きます。
【なぜダメなのか?】
・行番号のSMALL:小さい順に並ぶので 3, 5
・列番号のSMALL:小さい順に並ぶので 3, 6
これらを組み合わせると…
1つ目の答え:行3, 列3 → C3(間違い!)
2つ目の答え:行5, 列6 → F6(間違い!)
行と列を別々にソートしてしまうと、ペアの関係が崩れて、実在しない座標(お化け)を表示してしまうのです。


数式6:【正解例】ユニークIDを作って解決
ペアを崩さないためには、行と列を合体させて「固有のID」を作ってから並べ替える必要があります。
例えるなら、出席番号3番の佐藤さんと、6番の鈴木さんをバラバラにするのではなく、「3006」という背番号を作って管理するイメージです。
=IFERROR(
ADDRESS(
QUOTIENT(
SMALL(
IF(
($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),
ROW($A$1:$I$9)*1000+COLUMN($A$1:$I$9)
),
ROW(A1)
),
1000
),
MOD(
SMALL(
IF(
($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),
ROW($A$1:$I$9)*1000+COLUMN($A$1:$I$9)
),
ROW(A1)
),
1000
),
4
),
""
)【難易度:★★★★☆】【実用度:★★★★☆】
【ロジックの解説】
1.ROW($A$1:$I$9)*1000+COLUMN($A$1:$I$9)
行番号を1000倍して列番号を足します。例えば3行6列目なら「3006」というIDになります。


なぜ1000倍かというと、列番号が足されても桁上がりして行番号と混ざらないようにするためです。
100倍でも今回は足りますが、余裕を持って1000倍(あるいは10000倍)にするのが安全です。
2. SMALL
このIDの状態で並べ替えを行います。これならペアが崩れません。


3. QUOTIENT(ID, 1000)
IDを1000で割った「商」が行番号(3)に戻ります。
4. MOD(ID, 1000)
IDを1000で割った「余り」が列番号(6)に戻ります。


【ポイント】
割り算の商を求める際、INT関数を使うこともできますが、当ブログでは QUOTIENT(商)関数を推奨しています。
「商(QUOTIENT)」と「余り(MOD)」は対になる概念なので、セットで使うことで数式の意味(これは割り算のペアだよ!)が明確になるからです。
Excel 97以降に対応
最後に、まだ IFERROR も QUOTIENT もなかった時代の数式です。
「エラーだったら空白、そうでなければ計算」という処理をするために、同じ重たい計算を2回書く必要がありました。
数式7:レガシーな配列数式
=IF(
ISERROR(SMALL(IF(($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),ROW($A$1:$I$9)*1000+COLUMN($A$1:$I$9)),ROW(A1))),
"",
ADDRESS(
INT(
SMALL(IF(($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),ROW($A$1:$I$9)*1000+COLUMN($A$1:$I$9)),ROW(A1))
/1000
),
MOD(
SMALL(IF(($A$1:$I$9=11)*($B$1:$J$9=15)*($A$2:$I$10=7)*($B$2:$J$10=22),ROW($A$1:$I$9)*1000+COLUMN($A$1:$I$9)),ROW(A1)),
1000
),
4
)
)
【難易度:★★★★★】【実用度:★☆☆☆☆】
※Excel 2019以前の場合は、入力後に Ctrl + Shift + Enter で確定してください。
※スピルしないので、下にコピーして使ってください。
【ロジックの解説】
基本は数式6と同じですが、以下の点が異なります。
1. IF(ISERROR(計算), "", 計算)
エラー判定のために計算式を2回記述しています。非常に長くなりますが、これしか方法がありませんでした。
2. INT(ID / 1000)
Excel2003以前はQUOTIENT関数がなかったため、単純な割り算をしてINTで整数部を取り出すことで「商」を求めています。


まとめ:時代と共に進化する「検索」
最新のExcelなら TOCOL や FILTER で直感的に書ける処理も、昔は「行と列を合成してIDを作る」といった数学的な工夫が必要でした。
筆者のおすすめは、数式3です。
=FILTER(
TOCOL(ADDRESS(ROW(A1:I9),COLUMN(A1:I9),4)),
TOCOL(A1:I9&"_"&B1:J9&"_"&A2:I10&"_"&B2:J10="11_15_7_22")
)実務でこのような課題に遭遇したら、これをおすすめします。
誰が見ても比較的わかりやすいロジックで、馴染みのある関数のみを使用している上、数式も短いです。
更に、検索範囲が広がっても(例えばA1:AZ1000など)、文字列連結なら処理が比較的軽く、計算負荷が少ないです。
また、古いExcelをお使いの場合は、互換性重視の数式6(ユニークID方式)が鉄板です。
ぜひ、あなたのExcel環境に合わせて、最適な「ウォーリー探し」の数式を使ってみてください!


