如何在Scala中按另一个列表拆分列表

问题描述 投票:1回答:3

我是Scala的新手,我需要解决我的问题。想象一下,我有这些列表:

val list1 = List(1,2,3,4,5,6,7,8,9,10,11)
val list2 = List(6,5)

我的愿望是使用list2分割列表列表中的第一个列表来映射它。所以结果将是这样的:

val result = List(List(1,2,3,4,5,6), List(7,8,9,10,11))

如果我的list2是这样的:

val list2 = List(4,4,3)

结果将是:

val result = List(List(1,2,3,4),List(5,6,7,8),List(9,10,11))

做这个的最好方式是什么?

scala list split functional-programming
3个回答
2
投票

你可以使用scanLeftsplitAt的组合:

list2.scanLeft((List.empty[Int], list1)) { 
  case ((_, remaining), i) =>  remaining.splitAt(i)
}.unzip._1.tail

得到:

List(List(1, 2, 3, 4, 5, 6), List(7, 8, 9, 10, 11))

简要说明:scanLeft的每一步都将list1list1的其余元素保存在一个元组中。其余的元素根据下一个块的大小i进行拆分,其中ilist2的元素。最后,unzip._1抛弃了所有“剩余部分”,tail删除了第一个空虚元素。

请注意,由于列表结构是不可变的和持久的,因此在每个步骤中存储在元组的第二个组件中的中间结果不会占用任何额外的空间,它们仅仅是对list1尾部的引用。


1
投票

如果你正在做的是使用第二个列表作为第一个列表上的索引:

def indexedSplit[A](myList: List[A], indx: List[Int], acc: List[List[A]]): List[List[A]] = indx match{
  case Nil => acc.filter(_ != Nil).reverse
  case x :: xs => 
    val (h, t) = myList.splitAt(x)
    indexedSplit(t, xs, h :: acc)
}

其中您递归地遍历索引列表并在每个点的操作下拆分列表。最后,您过滤掉空列表并反转订单,因为您已按相反顺序累积。


1
投票
def foo[A](xs: List[A], ys: List[Int]): List[List[A]] = {
  val (result, _) = ys.foldLeft((List.empty[List[A]], xs)) { case ((acc, remaining), i) =>
    (remaining.take(i) :: acc, remaining.drop(i))
  }

  result.reverse
}

test("1") {
  val list1 = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
  val list2 = List(6, 5)
  val result = List(List(1, 2, 3, 4, 5, 6), List(7, 8, 9, 10, 11))

  foo(list1, list2) shouldBe result
}

test("2") {
  val list1 = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
  val list2 = List(4, 4, 3)
  val result = List(List(1, 2, 3, 4), List(5, 6, 7, 8), List(9, 10, 11))

  foo(list1, list2) shouldBe result
}
© www.soinside.com 2019 - 2024. All rights reserved.