处理 Set of Sets 并返回一个平面 Iterable

发布于 2024-10-13 11:41:31 字数 303 浏览 7 评论 0原文

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
val input=Set(Set("a","b"),Set("b","c"))

I want this:

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

What is the best functional approach for implementing such functionality?
Using yield keyword results in nested Iterables:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏日浅笑〃 2024-10-20 11:41:31

更新: 合并了使用 input.toSeq.flatten
的建议
而不是 input.toSeq flatMap { _.toSeq }

转换为单个值序列...

input.toSeq.flatten

...匹配...的组值

input.toSeq.flatten groupBy { identity }

...并计数

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

update: incorporated the suggestion to use input.toSeq.flatten
instead of input.toSeq flatMap { _.toSeq }

convert to a single sequence of values...

input.toSeq.flatten

...group values that match...

input.toSeq.flatten groupBy { identity }

...and count

input.toSeq.flatten groupBy { identity } mapValues { _.size }
不语却知心 2024-10-20 11:41:31

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

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

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

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

If you want to use for-comprehension and yield:

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

The code in your last line can be simplified (but does not what you want):

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

阿楠 2024-10-20 11:41:31

哦,天哪,那太丑了...

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]

根据 Kevin 的想法,合并可以写成

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")  
}

Oh boy, that's so ugly...

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

[Edit]

The Collection-API needs really a method for "merging" two Maps (or did I just overlook it???), e.g.

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)))

With this you could write something like:

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

[Edit2]

With Kevin's idea merge could be written as

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

Seems like my Scala-Fu is still too weak. What's the best way to express

(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")  
}

?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文