如何对列表中的所有元素组合执行操作?

时间:2017-10-23 17:25:01

标签: kotlin

我有多个列表,为了简单起见,我们说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>]

5 个答案:

答案 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,在这种情况下,RUnit

答案 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()