不明な数のリスト、長さの異なるリスト、およびタイプの異なるリストの場合は、次を使用できます。
def xproduct (xx: List [List[_]]) : List [List[_]] =
xx match {
case aa :: bb :: Nil =>
aa.map (a => bb.map (b => List (a, b))).flatten
case aa :: bb :: cc =>
xproduct (bb :: cc).map (li => aa.map (a => a :: li)).flatten
case _ => xx
}
あなたはそれを呼ぶでしょう
xproduct List (List ("a ", "b ", "c "), List ("x", "y"))
しかし、別の種類のリストでも呼び出すことができます。
scala> xproduct (List (List ("Beatles", "Stones"), List (8, 9, 10), List ('$', '€')))
res146: List[List[_]] = List(List(Beatles, 8, $), List(Stones, 8, $), List(Beatles, 8, €), List(Stones, 8, €), List(Beatles, 9, $), List(Stones, 9, $), List(Beatles, 9, €), List(Stones, 9, €), List(Beatles, 10, $), List(Stones, 10, $), List(Beatles, 10, €), List(Stones, 10, €))
リストを使用できない場合は、配列をリストに変換し、結果を配列に変換し直す必要があります。
アップデート:
怠惰なコレクションに向かう途中で、インデックス(0からcombination-size -1まで)からその位置での結果への関数マッピングを作成しました。モジュロと除算で簡単に計算できます。必要なのはほんの少しの集中です。
def combicount (xx: List [List[_]]): Int = (1 /: xx) (_ * _.length)
def combination (xx: List [List[_]], i: Int): List[_] = xx match {
case Nil => Nil
case x :: xs => x(i % x.length) :: combination (xs, i / x.length)
}
def xproduct (xx: List [List[_]]): List [List[_]] =
(0 until combicount (xx)).toList.map (i => combination (xx, i))
代わりにlongを使用しても、BigIntを使用しても問題ありません。
アップデート2、イテレータ:
class Cartesian (val ll: List[List[_]]) extends Iterator [List[_]] {
def combicount (): Int = (1 /: ll) (_ * _.length)
val last = combicount - 1
var iter = 0
override def hasNext (): Boolean = iter < last
override def next (): List[_] = {
val res = combination (ll, iter)
iter += 1
res
}
def combination (xx: List [List[_]], i: Int): List[_] = xx match {
case Nil => Nil
case x :: xs => x (i % x.length) :: combination (xs, i / x.length)
}
}