いきなり答える備忘録

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

(Excel)クロス結合(直積)を作る

 Excelで、関数によりクロス結合(CROSS JOIN、直積)を作成する方法です。
 近年の関数の拡充によって方法はいろいろ考えられるようになりましたが、いずれもちょっと面倒です。

  • TOCOL/TEXTBEFORE関数等を利用してクロス結合(直積)を作ることができます。
  • REDUCE/LAMBDA関数等を使う方法もあります。数値をそのまま取得できるのがメリットです。

手順

TOCOL/TEXTBEFORE関数等を使う方法

 文字列操作を利用する方法です。
 比較的理解はしやすいものの、数値が文字列に変換されるのが注意点です。また、区切り文字として文字列中で使われていない文字を選ぶ必要があります(ここでは「_」)。


 画像ではB列には3つの県名、C列には4つの品目が入力されています。
 これに対しE3セルに次のような式を入力して、これらのクロス結合(すべての組み合わせを表す12個の行)を出力しています。
 式は次のようになっています。

 E3セル

=LET(
x,TOCOL(B3:B5&"_"&TRANSPOSE(C3:C6)),
HSTACK(TEXTBEFORE(x,"_"),TEXTAFTER(x,"_"))
)

 まず「B3:B5&"_"&TRANSPOSE(C3:C6)」の部分により、県名と品目を「_」でつないだ文字列を全通り(12個)生成しています(下記参照)。
 そしてこれをTOCOL関数で縦1列に並べたものをLET関数によりxと名付けています。
 さらにTEXTBEFORE関数とTEXTAFTER関数を使い、xの各項目を「_」の前後に分割した列をそれぞれ生成し、HSTACK関数で横並びに表示させています。
 TOCOL関数の結果に対しTEXTSPLIT関数が直接使えれば話は早いのですが、TEXTSPLIT関数の第1引数に配列を与えた場合に最初の項目の列(この例では県名の列)しか返ってこないという仕様のためうまくいきません。


 なお、「B3:B5&"_"&TRANSPOSE(C3:C6)」の部分だけ実行すると次のようになります。
 これをTOCOL関数で縦1列に並べてさらに「_」の前後に分割し、2列に表示している、というわけです。

REDUCE/LAMBDA関数等を使う方法

 REDUCE/LAMBDA関数を利用する方法です。
 文字列操作を伴わないため数値が文字列に変換されません。


 データも結果も上記の例と全く同じで、E3セル内の式だけが異なります。
 式の内容は次のとおりです。

 E3セル

=DROP(
REDUCE("",B3:B5,
LAMBDA(a,b,VSTACK(a,IFNA(HSTACK(b,C3:C6),b)))),
1)

 字数こそ最初の例より短いですがちょっとややこしいです。
 B3:B5(=b、産地名)の1セルごとに、C3:C6(品目名)の4つのセルをムリヤリHSTACKしています。サイズが合わないので#N/Aエラーのセルが生じますが、IFNAでそこを産地名に変換しています。各産地についてこれを繰り返してVSTACKし、先頭の1行(空文字列)をDROPで削除して完成です。


 やっていることは面倒ですが、この方法では数値は数値のままにできるのがポイントです。


 余談ですが、3つの産地名に対して右側に1つの品目名をEXPANDするのを4回繰り返せばIFNAが要らなくて済みます。しかし最初の例と同じソートにできないためこうしました。EXPANDが左側に広げられる仕様なら良かったですが……