我有多个列表,为了简单起见,我们说2:
val names = listOf("John", "Tom")
val days = listOf(1, 2, 3)
我想用函数f: (String, Int): Unit
迭代这些可能值的所有组合:
f("John", 1)
f("John", 2)
f("John", 3)
f("Tom", 1)
f("Tom", 2)
f("Tom", 3)
我想找出在kotlin中这样做的惯用方法。在我的脑海中,我想这可以通过嵌套地图来完成。有点像:
a.map { itA ->
b.map { itB ->
f(itA, itB)
}
}
修改: 这似乎对我不起作用,因为它返回:
[() -> kotlin.collections.List<kotlin.Unit>, () -> kotlin.collections.List<kotlin.Unit>]
答案 0 :(得分:4)
names.forEach {
i -> days.forEach { j -> f(i, j)}
}
是最接近的:
private fun f(i: String, j: Int) = println("$i,$j")
示例:强>
John,1
John,2
John,3
Tom,1
Tom,2
Tom,3
结果:
{{1}}
答案 1 :(得分:1)
常规for
循环有什么问题?
for (name in names) for (day in days) f(name, day)
答案 2 :(得分:0)
如果您确实需要f
的结果,请执行以下操作:
fun <T1, T2, R> combine(
first: Iterable<T1>,
second: Iterable<T2>,
combiner: (T1, T2) -> R
): List<R> = first.flatMap { firstItem -> second.map { secondItem -> combiner(firstItem, secondItem) } }
@Test fun test() {
val names = listOf("John", "Tom")
val days = listOf(1, 2, 3)
val result = combine(days, names, { day, name -> "${day}. ${name}" })
@Suppress("DEPRECATION")
kotlin.test.assert(result) {
shouldBe(listOf(
"1. John",
"1. Tom",
"2. John",
"2. Tom",
"3. John",
"3. Tom"
))
}
}
注意:它也适用于println
,在这种情况下,R
为Unit
。
答案 3 :(得分:0)
您要查找的输出名称是Cartesian Product。
如果您不需要所有的组合,而只是搜索一个或多个,则可以将其设为延迟生成的序列:
private fun <A, B> lazyCartesianProduct(
listA: Iterable<A>,
listB: Iterable<B>
): Sequence<Pair<A, B>> =
sequence {
listA.forEach { a ->
listB.forEach { b ->
yield(a to b)
}
}
}
然后,您只能映射,过滤等所需内容:
val names = listOf("John", "Tom")
val days = listOf(1, 2, 3)
lazyCartesianProduct(names, days)
.map { it.toSomethingElse() }
.find { it.isWhatImLookingFor() }
答案 4 :(得分:0)
您可以通过平面映射生成不同的组合。
val names = listOf("John", "Tom")
val days = listOf(1, 2, 3)
val isSht = listOf(true, false)
val combz =
names.flatMap { name ->
days.flatMap { day ->
isSht.map { isSht -> "${day} ${isSht}" }
}.map { daySht -> "${daySht} ${name}" }
}.toList()