如何在Kotlin中按块映射列表

4

我经常使用类似下面的数据源(伪代码,不是任何特定语法,只是为了说明):

list = {
  "XLabel", 
  "XDescription", 
  "YLabel", 
  "YDescription", 
  "ZLabel", 
  "ZDescription"
}

期望的输出结果是:
list = { 
  MyClass("XLabel", "XDescription"), 
  MyClass("YLabel", "YDescription"), 
  MyClass("ZLabel", "ZDescription")
}

有没有比使用fold()更简洁的方法,将其折叠到一个新列表中?我也拒绝做一些奇怪的事情,比如list.partition().zip()

我基本上想要一个更强大的map,它能像mapChunks(it1, it2 -> MyClass(it1, it2)) 这样工作,其中分块是函数的一部分,因此它变得容易和好看。(我的示例中,列表被分为两个块,但3也是一个普遍的用例。)

这个函数存在吗?或者最惯用的方法是什么?


“我也拒绝做一些奇怪的事情,比如list.partition().zip()或者...” - 这句话好像不完整? - Alex Yu
5个回答

8

您可以使用chunked函数,然后对结果进行map。如果您解构lambda参数,则语法非常接近您想要的:

list.chunked(2)
    .map { (it1, it2) -> MyClass(it1, it2) }
    // Or use _it_ directly: .map { MyClass(it[0], it[1]) }

5
我认为 windowed 方法应该能够实现你想要的功能。
lst.windowed(size = 2, step = 2, partialWindows = false) { innerList -> MyClass(innerList[0], innerList[1]) }

你也可以使用chunked, 但它会在底层调用windowed。但是,使用chunked你可能会得到比预期更少元素的列表。

编辑以回答@android developer关于获取列表索引的问题。

val lst = listOf(7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
val windowedList = lst.mapIndexed { index, it -> index to it }
    .windowed(size = 2, step = 2, partialWindows = false) {
        it[0].first
    }
println(windowedList)

将产生输出

[0, 2, 4, 6, 8]

这实际上很棒,但我认为你忘记了 windowedstep 参数,它应该与 size 相同。另外,你知道是否可以获取每个列表生成的索引吗?这有助于错误日志... - android developer
@androiddeveloper 你说得对,我确实漏掉了 step 参数(我想我最初没有仔细阅读问题)。我不认为 windowedchunked 函数会传递索引。但是,您可以添加一个 mapIndexed 步骤并创建一个索引到值的 Pair,然后执行 windwed 函数,这样您就可以获得索引信息了。 - Matt Berteaux
我实际上发现windowed很有用。我不明白chunked是做什么的。类似吗?相同吗?你能否更新你的答案,并展示如何使用你现在提到的其他解决方案来完成它? - android developer
1
@androiddeveloper chunked 基本上相當於使用相同的 sizestep 值和 particalWindows 設為 true 時呼叫 windowed - Matt Berteaux
哦,所以这是更常见的情况,我无论如何都使用了。谢谢!您能否更新答案以包括“chunked”代码段? - android developer

1

除了现有的答案,您可以使用chunked函数,并将转换lambda作为其第二个参数传递:

list.chunked(2) { (label, description) -> MyClass(label, description) }

这种方式更加高效,因为两个元素的临时列表会在所有块中重复使用。

0

0
你可以创建一个扩展函数,例如 mapChunks,并重复使用它:
fun List<String>.mapChunks(): List<MyClass> {
    return chunked(2).map { MyClass(it[0], it[1]) }
}

val list1 = listOf(
    "XLabel",
    "XDescription",
    "YLabel",
    "YDescription",
    "ZLabel",
    "ZDescription"
)
val result1 = list1.mapChunks()

val list2 = listOf(
        "XLabel1",
        "XDescription1",
        "YLabel1",
        "YDescription1",
        "ZLabel1",
        "ZDescription1"
)
val result2 = list2.mapChunks()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接