我想你想要这样的东西(使用 Shapeless):
import shapeless._
object CartesianProduct
extends App {
def cross(a: Iterable[Iterable[_]]): Iterable[HList] = {
// If a is empty, return HNil to signal the end of this heterogenous list.
if(a.isEmpty) Iterable(HNil)
// Otherwise, create a new heterogeneous list for each element in this list,
// prefixed to each heterogeneous list for the remainder.
else for {
i <- a.head // For each element in the head sequence
t <- cross(a.tail) // For each heterogenous list in the output sequence
} yield i :: t // Create a new heterogeneous list
}
val data = List(List(1, 2, 3), List("a", "b"), List(-1, -2, -3))
val result = cross(data)
println(result)
}
结果是:
List(1 :: a :: -1 :: HNil, 1 :: a :: -2 :: HNil, 1 :: a :: -3 :: HNil, 1 :: b :: -1 :: HNil, 1 :: b :: -2 :: HNil, 1 :: b :: -3 :: HNil, 2 :: a :: -1 :: HNil, 2 :: a :: -2 :: HNil, 2 :: a :: -3 :: HNil, 2 :: b :: -1 :: HNil, 2 :: b :: -2 :: HNil, 2 :: b :: -3 :: HNil, 3 :: a :: -1 :: HNil, 3 :: a :: -2 :: HNil, 3 :: a :: -3 :: HNil, 3 :: b :: -1 :: HNil, 3 :: b :: -2 :: HNil, 3 :: b :: -3 :: HNil)
更新:你可以不使用Shapeless来做到这一点吗?
这个怎么样:
object CartesianProduct
extends App {
def cross(a: Iterable[Iterable[_]]): Iterable[List[_]] = {
// If a is empty, return Nil to signal the end of this list of Anys.
if(a.isEmpty) Iterable(Nil)
// Otherwise, create a new list of Anys for each element in this iterable,
// prefixed to each list of Anys for the remainder.
else for {
i <- a.head // For each element in the head sequence
t <- cross(a.tail) // For each list of Anys in the output sequence
} yield i :: t // Create a new list of Anys
}
val data = List(List(1, 2, 3), List("a", "b"), List(-1, -2, -3))
val result = cross(data)
println(result)
}
它实际上输出List[List[Any]]:
List(List(1, a, -1), List(1, a, -2), List(1, a, -3), List(1, b, -1), List(1, b, -2), List(1, b, -3), List(2, a, -1), List(2, a, -2), List(2, a, -3), List(2, b, -1), List(2, b, -2), List(2, b, -3), List(3, a, -1), List(3, a, -2), List(3, a, -3), List(3, b, -1), List(3, b, -2), List(3, b, -3))
(类型推断丢失的原因是,首先,您的函数签名中没有任何泛型类型,因此泛型类型_ 相当于说您的可迭代对象包含Any 值。其次,您'然后将这些Any 值添加到List。因此列表包含异构元素(在这种情况下为Int 和String)。对结果执行任何操作都意味着您将不得不强制转换类型,或模式匹配。为了确定是否有更好的方法,我不得不问你用这个函数做什么?)
我认为,在一般情况下,返回元组列表是不可能的(因为您需要确定输入中有多少可迭代项才能创建具有这么多值的元组)。
更新2:如果你想以元组的形式输出,你显然需要知道传递给函数的每个迭代的数量和类型。 Shapeless 版本如下所示:
// Convert result to a tuple.
val generic = Generic[Tuple3[Int, String, Int]]
val tupleResult = result.map {l =>
val t = l.asInstanceOf[Int :: String :: Int :: HNil]
generic.from(t)
}
println(tupleResult)
而非Shapeless 版本看起来像这样:
val tupleResult = result.map {l =>
(
l.head.asInstanceOf[Int],
l.tail.head.asInstanceOf[String],
l.tail.tail.head.asInstanceOf[Int]
)
}
println(tupleResult)
在这两种情况下,输出都是:
List((1,a,-1), (1,a,-2), (1,a,-3), (1,b,-1), (1,b,-2), (1,b,-3), (2,a,-1), (2,a,-2), (2,a,-3), (2,b,-1), (2,b,-2), (2,b,-3), (3,a,-1), (3,a,-2), (3,a,-3), (3,b,-1), (3,b,-2), (3,b,-3))