いきなり答える備忘録

Google Workspace・Microsoft 365・LibreOfficeなどに関するメモ

(Excel)クロス抽出の逆の抽出をする

 Excelで、クロス抽出とは逆に表内の値から見出し列(行)の内容を抽出する方法です。
 やり方を3つ紹介しますが、最後のものでは検索値が複数みつかるときにすべて抽出できます。

XLOOKUP/LAMBDA/BYROW(BYCOL)関数を使う方法

 次の画像では、G3セルに入力されている担当者名を担当表から検索し、対応する見出し(日、時間帯)の2つの値を求めています。
 (※H3セルには表示形式「日付」を適用しています。以下同様)

 H3,I3セル

=XLOOKUP(TRUE,BYROW(C3:E6,LAMBDA(a,COUNTIF(a,G3)>0)),B3:B6)
=XLOOKUP(TRUE,BYCOL(C3:E6,LAMBDA(a,COUNTIF(a,G3)>0)),C2:E2)

 まずH3セルの式(日付を抽出)ですが、「BYROW(C3:E6,LAMBDA(a,COUNTIF(a,G3)>0))」の部分がポイントです。これはC3:E6の範囲にaという名前を付けて、その各行ごとにG3セルの値(鈴木)をカウントし、0より大きいかどうかを判定しています。結果的に「鈴木」がある行はTRUEに、そうでない行はFALSEに換算されます。そこからTRUEを検索して、対応するB3:B6中の行を抽出することで「2023/1/6」が得られています。
 I3セルについても同様で、BYCOL関数を使って列方向に同じことをやっています。



 「BYROW(~LAMBDA(~))」の部分だけ実行すると次のようになります。
 ここからXLOOKUP関数でTRUEを検索することで「2023/1/6」を抽出できることがわかります。

 


 この方法は基本的に次の方法より簡潔ですが、式中の検索値「G3」を拡張してもスピルしません。
 そこで次の画像では絶対参照とフィルコピーを使って、G3,G4セルの2つの担当者に対応する日付と時間帯を抽出しています。

 H3,I3セル(下方にフィルコピー)

=XLOOKUP(TRUE,BYROW(C$3:E$6,LAMBDA(a,COUNTIF(a,G3)>0)),B$3:B$6)
=XLOOKUP(TRUE,BYCOL(C$3:E$6,LAMBDA(a,COUNTIF(a,G3)>0)),C$2:E$2)

XLOOLUP/TOCOL関数を使う方法

 次の画像では上記の例と同様に、G3セルに入力されている担当者名を担当表から検索し、対応する見出し(日、時間帯)の2つの値を求めています。

 具体的にはH3セル、I3セルに次のような式を入力して求めています。

 H3,I3セル

=XLOOKUP(G3,TOCOL(C3:E6),TOCOL(IF(B3:B6&C2:E2<>"",B3:B6)))
=XLOOKUP(G3,TOCOL(C3:E6),TOCOL(IF(B3:B6&C2:E2<>"",C2:E2)))

 

 H3セル(日付を抽出する)の例で詳細を見てみます。

 XLOOKUP関数の第2引数「TOCOL(C3:E6)」で担当者名を縦1列に並べています。
 同じく第3引数の「TOCOL(IF(B3:B6&C2:E2<>"",B3:B6))」で、日付を縦1列に並べています。このときIF関数を使い(ちょっとムリヤリですが)各日付を3つ(=時間帯の見出しの数)ずつ生成して縦に並べることで、担当者(第2引数)と日付(第3引数)の対応付けが元の担当表における対応付けと同じものになります。
 あとはこの2つの列に対しXLOOKUPで担当者名を検索すれば、担当者名に対応する日付が得られるというわけです。時間帯についても理屈は同じです。


 複数の氏名を検索する場合はスピルを利用します。2つの式の第1引数をそれぞれ「G3:G4」に置き換えるだけでOKです。

 以下は備考です。

  • 元の表の見出しに何も入ってないと(IF関数の内容が原因で)おかしな結果になります。
  • 検索値(担当者名)が複数見つかる場合、最も上の行の最も左のセルに対応する見出しが返ります。左を優先したい場合は関数をいじっても出来ますが元の表をTRANSPOSEした方が早いです。
  • 上記の2つの式の第3引数をHSTACKで1つにまとめれば1つの式で2列出力できます。ただし検索値(担当者名)を複数与えたときに左の列(日)しか返りません。

FILTER/TOCOL関数を使う方法

 上記の方法中のXLOOKUP関数をFILTER関数に簡単に置き換えれば、検索値(担当者名)が複数存在するときに、対応する見出しをすべて抽出することができます。
 (※H3セル以降には表示形式「日付」を適用しています)

 H3,I3セル

=FILTER(TOCOL(IF(B3:B6&C2:E2<>"",B3:B6)),TOCOL(C3:E6)=G3)
=FILTER(TOCOL(IF(B3:B6&C2:E2<>"",C2:E2)),TOCOL(C3:E6)=G3)

 考え方は1つ上のXLOOKUPの例と全く同じで、関数の特性により条件の与え方が異なるだけです。
 備考についてもXLOOKUPの例とおおむね同様です。


 なお細かい話になりますが一発で2列出力させるときに引数をHSTACKするより見出し同士の直積を作って検索した方が早そうな感じがします。ただ、比較的簡単に生成するやり方だと数値や日付が文字列になってしまう難点があります。

 H3セル

=LET(x,FILTER(TOCOL(B3:B6&"_"&C2:E2),TOCOL(C3:E6)=G3),
HSTACK(TEXTBEFORE(x,"_"),TEXTAFTER(x,"_"))
)