Splitting a Scala List into parts using a given list of part sizes.[Partitioning]

随声附和 提交于 2020-01-02 12:21:00

问题


I got two lists:

val list1:List[Int]   =  List(5, 2, 6)

val list2:List[Any]  =  List("a", "b", "c", "d", "e", "f", "g", "h", "i", "j","k")

such that list1.sum >= list2.size

I want a list of lists formed with elements in list2 consecutively with the sizes mentioned in list1.

For example:

if list1 is List(5,2,4) the result I want is:

List(List("a", "b", "c", "d", "e"),List("f", "g"),List("h", "i", "j","k"))

if list1 is List(5,4,6) the result I want is:

List(List("a", "b", "c", "d", "e"),List("f", "g","h", "i"),List("j","k"))

How can I do that with concise code.


回答1:


Turn list2 into an Iterator then map over list1.

val itr = list2.iterator
list1.map(itr.take(_).toList)
//res0: List[List[Any]] = List(List(a, b, c, d, e), List(f, g), List(h, i, j, k))

update: While this appears to give the desired results, it has been pointed out elsewhere that reusing the iterator is actually unsafe and its behavior is not guaranteed.

With some modifications a safer version can be achieved.

val itr = list2.iterator
list1.map(List.fill(_)(if (itr.hasNext) Some(itr.next) else None).flatten)

-- or --

import util.Try
val itr = list2.iterator
list1.map(List.fill(_)(Try(itr.next).toOption).flatten)



回答2:


you can slice on list2 based on the size you get from list1,

  def main(args: Array[String]): Unit = {

    val groupingList: List[Int] = List(5, 2, 4)
    val data = List("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k")

    //0, 5
    //5, (5 + 2)
    //5 + 2, (5 + 2 + 4)

    val grouped = groupingList.zipWithIndex.map { case (_, index) =>
      val start = groupingList.slice(0, index).sum
      val end = groupingList.slice(0, index + 1).sum

      data.slice(start, end)
    }

    println(grouped)
  }

result: List(List(a, b, c, d, e), List(f, g), List(h, i, j, k))

Also read: How slice works




回答3:


i like show it using ex list1=List("one","two","three") List[String] = List(one, two, three)

list2=List("red","green","blue") List[String] = List(red, green, blue)

list1::list2 List[java.io.Serializable] = List(List(one, two, three), red, green, blue)

var listSum=list1::list2 List[java.io.Serializable] = List(List(one, two, three), red, green, blue)

listSum List[java.io.Serializable] = List(List(one, two, three), red, green, blue)

we can "::" for insert one list to another list in Scala




回答4:


Just found by me, even the following code worked, but the code posted by jwvh appears more concise than this, and I understand making list1 a Vector makes more sense regarding performance of element access in the following code:

list1.scan(0)(_+_).sliding(2).toList.map(x=>list2.drop(x(0)).take(x(1)-x(0)))

or

list1.scan(0)(_+_).zip(list1).map(x=>list2.drop(x._1).take(x._2))

list1.scan(0)(_+_).sliding(2).map(x=>list2.slice(x(0),x(1))).toList


来源:https://stackoverflow.com/questions/51335281/splitting-a-scala-list-into-parts-using-a-given-list-of-part-sizes-partitioning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!