处理集合并返回平面可迭代

时间:2011-01-20 11:37:06

标签: scala functional-programming yield loops

val input=Set(Set("a","b"),Set("b","c"))

我想要这个:

Map("a"->1,"b"->2,"c"->1)

实现此类功能的最佳功能方法是什么? 在嵌套的Iterables中使用yield关键字结果:

output = for(firstlevel<-input) yield for(item<-firstlevel) yield item

3 个答案:

答案 0 :(得分:8)

更新 纳入了使用input.toSeq.flatten的建议 而不是input.toSeq flatMap { _.toSeq }

转换为单个值序列...

input.toSeq.flatten

...匹配...的组值

input.toSeq.flatten groupBy { identity }

...并计算

input.toSeq.flatten groupBy { identity } mapValues { _.size }

答案 1 :(得分:2)

如果你想使用for-understanding和yield:

output = for{
    (set,idx) <- input.zipWithIndex
    item <- set
} yield (item -> idx)

最后一行中的代码可以简化(但不是你想要的):

output = for{
    set <- input
    item <- set
} yield item

答案 2 :(得分:1)

哦,小伙子,那太丑了......

input.foldLeft(Map[String,Int]())((m,s) => 
   s.foldLeft(m)((n,t) => n + (t -> (1 + n.getOrElse(t,0)))))

<强> [编辑]

Collection-API真的需要一种“合并”两个地图的方法(或者我只是忽略了它),例如。

def merge[A,B](m1: Map[A,B], m2:Map[A,B])(f: (B,B)=>B):Map[A,B] =
  m1.foldLeft(m2)((m,t) =>
      m + (t._1 -> m.get(t._1).map(k => f(k,t._2)).getOrElse(t._2)))

有了这个,你可以这样写:

input.map(_.map(x => x -> 1).toMap).reduceLeft(merge(_,_)(_+_))

<强> [EDIT2]

凯文的想法合并可以写成

def merge[A,B](m1: Map[A,B], m2:Map[A,B])(f: (B,B)=>B):Map[A,B] =
   m1.keys ++ m2.keys map {k => k ->
        List(m1.get(k), m2.get(k)).flatten.reduceLeft(f)} toMap
似乎我的Scala-Fu仍然太弱了。什么是最好的表达方式

(o1,o2) match {
    case (Some(x),Some(y)) => Some(f(x,y))    
    case (Some(x), _) => Some(x)    
    case (_, Some(y)) => Some(y)    
    case => error("crack in the time-space-continuum")  
}