将列表提取到多个不同的列表

时间:2017-11-10 16:42:13

标签: scala list

如何在Scala中将Scala列表提取到具有多个不同列表的List?

val l = List(1,2,6,3,5,4,4,3,4,1)

List(List(1,2,3,4,5,6),List(1,3,4),List(4))

4 个答案:

答案 0 :(得分:4)

这是一种(效率相当低)的方法:按值分组,按组大小排序结果,然后使用第一组作为原始组的每索引扫描的基础来构建不同的列表:

scala> val l = List(1,2,6,3,5,4,4,3,4,1)
l: List[Int] = List(1, 2, 6, 3, 5, 4, 4, 3, 4, 1)

scala> val groups = l.groupBy(identity).values.toList.sortBy(- _.size)
groups: List[List[Int]] = List(List(4, 4, 4), List(1, 1), List(3, 3), List(5), List(6), List(2))

scala> groups.head.zipWithIndex.map { case (_, i) => groups.flatMap(_.drop(i).headOption) }
res9: List[List[Int]] = List(List(4, 1, 3, 5, 6, 2), List(4, 1, 3), List(4))

答案 1 :(得分:2)

在@TzachZohar的第一个答案中分组之后的另一种方法是继续从每个列表中取一个元素,直到所有列表都为空:

val groups = l.groupBy(identity).values

Iterator
  // continue removing the first element from every sublist, and discard empty tails
  .iterate(groups)(_ collect { case _ :: (rest @ (_ :: _)) => rest } )
  // stop when all sublists become empty and are removed
  .takeWhile(_.nonEmpty)
  // build and sort result lists 
  .map(_.map(_.head).toList.sorted)
  .toList

答案 2 :(得分:0)

这是另一种选择 - 扫描输入N次,N是单个值的最大重复次数:

// this function splits input list into two: 
// all duplicate values, and the longest list of unique values
def collectDistinct[A](l: List[A]): (List[A], List[A]) = l.foldLeft((List[A](), List[A]())) {
  case ((remaining, distinct), candidate) if distinct.contains(candidate) => (candidate :: remaining, distinct)
  case ((remaining, distinct), candidate) => (remaining, candidate :: distinct)
}

// this recursive function takes a list of "remaining" values,
// and a list of distinct groups, and adds distinct groups to the list
// until "remaining" is empty
@tailrec
def distinctGroups[A](remaining: List[A], groups: List[List[A]]): List[List[A]] = remaining match {
  case Nil => groups
  case _ => collectDistinct(remaining) match {
    case (next, group) => distinctGroups(next, group :: groups)
  }
}

// all second function with our input and an empty list of groups to begin with:
val result = distinctGroups(l, List())

答案 3 :(得分:0)

考虑这种方法:

trait Proc {
  def process(v:Int): Proc
}
case object Empty extends Proc {
  override def process(v:Int) = Processor(v, Map(0 -> List(v)), 0)
}
case class Processor(prev:Int, map:Map[Int, List[Int]], lastTarget:Int) extends Proc {
  override def process(v:Int) = {
    val target = if (prev==v) lastTarget+1 else 0
    Processor(v, map + (target -> (v::map.getOrElse(target, Nil))), target)
  }
}

list.sorted.foldLeft[Proc](Empty) {
  case (acc, item) => acc.process(item)
}

这里我们有简单的状态机。我们使用初始状态' Empty'迭代排序列表。一旦“空”'处理项目,它产生下一个状态'处理器'。 处理器具有以前的价值' prev'并已累计的已分组项目的地图。它还有lastTarget - 最后一次写入的列表索引。 唯一的事情'处理器'确实计算当前处理项目的目标:如果它与之前的处理项目相同,则采用下一个索引,否则从索引0开始。