将List [List [Int]]展平,同时仅保留选定的成员

时间:2012-02-27 13:08:24

标签: scala scala-collections

整数2..12:

的素数因子列表[List [Int]]
List(List(2), List(3), List(2, 2), List(5), List(3, 2), 
     List(7), List(2, 2, 2), List(3, 3), List(5, 2), 
     List(11), List(3, 2, 2))

需要将其展平,以使得结果数据结构仅包含每个素数的最长序列(最大功率):

List(2,2,2,3,3,5,7,11)

例如,除了两个最强大的力量之外的所有力量: 列表(列表( 2 ),List(3),List( 2,2 ),List(5),List(3 ,2 )          列表(7),列表( 2,2,2 ),列表(3,3),列表(5 ,2 ),          列表(11),列表(3 ,2,2 ))

在初始列表中,素数的子列表总是按降序排序。

努力寻找一种优雅的,最好是≤O(n)的解决方案。

我的解决方案远非理想:

xs.flatMap(l=> l.groupBy(x=>x)).map(x=>(x._1,x._2.length)).
   groupBy(_._1).mapValues(_.maxBy(_._2)).values.
   map(x=>List.fill(x._2) (x._1)).flatten

3 个答案:

答案 0 :(得分:1)

这比你的要短得多;它在概念上足够接近我希望你能弄明白:

xs.flatMap(_.groupBy(x=>x)).groupBy(_._1).
  flatMap(_._2.sortBy(- _._2.length).head._2).toSeq.sorted

答案 1 :(得分:1)

经过一些分析后,问题归结为两个排序列表的简单合并,但略有不同 - 它必须只添加一次重复元素:

merge(List(5,3,3,2),List(7,5,3,2,2)

必须产生:

List(7,5,3,3,2,2)

一旦有了这样精彩的merge功能,列表清单就可以从左到右简单地减少。

解决方案

def merge (xs:List[Int],ys:List[Int]):List[Int] = (xs,ys) match{
  case (Nil,_)         => ys
  case (_,Nil)         => xs
  case (x::xxs,y::yys) => if (x==y) x::merge(xxs,yys) 
                          else if (x>y) x::merge(xxs,ys) 
                          else y::merge(xs,yys)
}

// note the simplicity of application
ll reduce merge

尾递归版merge - 避免长列表上的堆栈溢出:

def merge (xs:List[Int],ys:List[Int]) = {
  def m (rs:List[Int],xs:List[Int],ys:List[Int]):List[Int] = (xs,ys) match {
    case (Nil,_)         => ys reverse_:::rs
    case (_,Nil)         => xs reverse_:::rs
    case (x::xxs,y::yys) => if (x==y) m(x::rs,xxs,yys) 
                            else if (x>y) m(x::rs,xxs,ys) 
                            else m(y::rs,xs,yys)
  }

  m(Nil,xs,ys).reverse   
}

merge的更快命令版本:

def merge (x:List[Int],y:List[Int]) = {
  var rs = new scala.collection.mutable.ListBuffer[Int]()
  var xs = x
  var ys = y
  while(!xs.isEmpty && !ys.isEmpty) {
    if (xs.head>ys.head) {
      rs+=xs.head
      xs=xs.tail
    } else if(xs.head==ys.head) {
      rs+=xs.head
      xs=xs.tail
      ys=ys.tail
    } else {
      rs+=ys.head
      ys=ys.tail          
    }
  }
  rs ++= xs ++= ys toList
}

答案 2 :(得分:0)

val ll = List(List(2), List(3), List(2, 2), List(5), List(3, 2),  
     List(7), List(2, 2, 2), List(3, 3), List(5, 2), 
     List(11), List(3, 2, 2))
val s = ll.flatten toSet 
s.map (n => ll.map (l => (n, l.count (_ == n)))).map (l => (l(0) /: l.tail) ((a, b) => if (a._2 > b._2) a else b))

产生

scala.collection.immutable.Set[(Int, Int)] = Set((7,1), (11,1), (2,3), (5,1), (3,2))

扩展因子并对它们进行排序,生成List(2,2,2,3,3,5,7,11)留作练习。