如何在Kotlin中组合两个不同的长度列表?

时间:2019-03-28 18:19:31

标签: java android kotlin kotlin-android-extensions

我想组合两个不同的长度列表。例如;

val list1 = listOf(1,2,3,4,5)
val list2 = listOf("a","b","c")

我想要这样的结果

(1,"a",2,"b",3,"c",4,5)

有什么建议吗?

6 个答案:

答案 0 :(得分:2)

您可以为此使用.zip函数

list1.zip(list2){ a,b -> listOf(a,b)}.flatten()

唯一的问题是,它将仅处理带有两个集合的元素,因此,如果(如示例中所示)具有不同的大小,则它将不起作用

另一种选择是添加特定标记并对其进行过滤,或者仅使用迭代器。我发现了一种sequence{..}函数的优雅解决方案

 val result = sequence {
    val first = list1.iterator()
    val second = list2.iterator()
    while (first.hasNext() && second.hasNext()) {
      yield(first.next())
      yield(second.next())
    }

    yieldAll(first)
    yieldAll(second)
  }.toList()

答案 1 :(得分:1)

  1. 如果源列表中的元素可以在结果列表中以任意顺序出现,则
>>> list1 + list2
res12: kotlin.collections.List<kotlin.Any> = [1, 2, 3, 4, 5, a, b, c]
  1. 如果源列表中的元素应在结果列表中交替出现,并且list1长于list2,则
>>> list1.zip(list2).flatMap { listOf(it.first, it.second) } + list1.drop(list2.size)
res16: kotlin.collections.List<kotlin.Any> = [1, a, 2, b, 3, c, 4, 5]

答案 2 :(得分:1)

您可以这样做:

val mergedList = with(setOf(list1, list2).sortedByDescending { it.count() }) {
    first().mapIndexed { index, e ->
        listOfNotNull(e, last().getOrNull(index))
    }
}.flatten()

首先,将两个列表都放在Set中,然后按产生列表列表的元素数对其进行排序(降序)。

第一个具有最多元素的列表将用于迭代。

使用mapIndexed可以使用index访问第二个列表中的相应元素。如果不存在,将返回null,并由listOfNotNull过滤掉。最后,将列表的结果列表弄平,并得到所需的结果:

  

[1,a,2,b,3,c,4,5]

答案 3 :(得分:0)

您的列表是不可转换的类型(整数和字符串),因此您必须具有MutableList<Any>才能添加两种类型:

val allItems = mutableListOf<Any>(1,2,3,4,5)
val list2 = listOf("a","b","c")
allItems.addAll(list2)

答案 4 :(得分:0)

我认为Eugenes的答案已经包含了组合两个列表(无论是zip还是组合所有元素)所需的全部知识。

如果您要组合任意数量的列表(每个交替列表一项),您可能还对以下方法感兴趣:

fun combine(vararg lists: List<*>) : List<Any> = mutableListOf<Any>().also {
  combine(it, lists.map(List<*>::iterator))
}

private tailrec fun combine(targetList: MutableList<Any>, iterators: List<Iterator<*>>) {
  iterators.asSequence()
          .filter(Iterator<*>::hasNext)
          .mapNotNull(Iterator<*>::next)
          .forEach { targetList += it }
  if (iterators.asSequence().any(Iterator<*>::hasNext))
    combine(targetList, iterators)
}

调用它的方式如下所示,并导致注释中显示的值:

combine(list1, list2) // List containing: 1, "a", 2, "b", 3, "c", 4, 5
combine(list1, list2, listOf("hello", "world")) // 1, "a", "hello", 2, "b", "world", 3, "c", 4, 5

可以使用以下代码来实现Eugenes答案第二部分的简化方法;当然,当您返回列表时不再懒惰;-)(但也许您甚至直接将其翻译为列表,所以您也可以使用此方法):

fun List<Any>.combine(other: List<Any>) : List<Any> = mutableListOf<Any>().also {
  val first = iterator()
  val second = other.iterator()
  while (first.hasNext() || second.hasNext()) {
    if (first.hasNext()) it.add(first.next())
    if (second.hasNext()) it.add(second.next())
  }
}

调用它的方式如下:

list1.combine(list2)

答案 5 :(得分:0)

这是我的看法:

fun <T> zip(vararg iterables: Iterable<T>): List<T> = iterables
.map { it.iterator() }
.toList()
.let { iterators ->
    mutableListOf<T>()
        .also { list ->
            while (
              iterators.any {if (it.hasNext()) list.add(it.next()) else false }
            ) { }
        }
}