【问题标题】:Scala - reduce functionScala - 减少函数
【发布时间】:2014-08-04 16:07:31
【问题描述】:

如何在 Scala 中使用 reduce 函数?有这样的内置功能吗? 我已经实现了一个程序来查找 scala 中的字数。

object count {
    def main(args: Array[String]) {
        val fruits = List("apple", "apple", "orange", "apple", "mango", "orange")
        val word = fruits.flatMap(_.split("\n"))
        val Map = word.map(word => (word,1)).groupBy(_._1)
        val reduce = Map.map(word => (word._1,word._2.foldLeft(0)((sum,c) => sum+ c._2)))
        println(reduce)     }} 

如何用reduce函数替换foldleft?

【问题讨论】:

  • 有一个reduce,但foldLeft在这种情况下更合适,因为reduce不接受默认值,所以它会在空列表上失败。
  • 如果我们改用reduce,函数会是什么样子?
  • 我刚刚对此表示赞同。然而,在当前状态下,它的措辞方式需要改进......但我仍然认为这个问题具有一定的教学价值,并且对中级/初学者 scala 用户很有用

标签: scala mapreduce word-count


【解决方案1】:

上面的整个例子都应该这样实现

fruits groupBy(word => word) mapValues(_.size)

或者像这样代替折叠

val reduce = Map.map(word => (word._1,word._2.size))

但如果你绝对肯定必须在相同的代码中使用 reduce,它会是这样的

val reduce = Map.map(word => (word._1,word._2.map(_=>1).reduce(_+_)))

【讨论】:

  • 很酷的例子。对于我使用 Scala 版本 2.11.4,第二条语句出错,但这有效: fruits groupBy(word => word) map(word => (word._1,word._2.size))
  • 感谢您的精彩回答。顺便说一句,当参数和返回值相同时,也可以使用 (identity) 而不是使用 (word => word)。
【解决方案2】:

您的示例可以更简单地完成如下:

> fruits.groupBy(identity).mapValues(_.size) 
res176: Map[String, Int] = Map("mango" -> 1, "orange" -> 2, "apple" -> 3)

但是,如果您想并行化并使用 MapReduce 模式,reduce 在这里很有用。如果您不并行化,您只需按顺序减少列表 (1,1,1,1...)。比较:

> List(1,1,1,1,1,1,1).reduce{(a,b) => println(s"$a+$b=${a+b}"); a + b} 
1+1=2
2+1=3
3+1=4
4+1=5
5+1=6
6+1=7
res187: Int = 7

使用并行版本(注意par 方法):

> List(1,1,1,1,1,1,1).par.reduce{(a,b) => println(s"$a+$b=${a+b}"); a + b} 
1+1=2
1+1=2
1+2=3
1+1=2
2+2=4
3+4=7
res188: Int = 7

您可以通过如下定义常用的reduceByKey 函数来在您的案例中使用 MapReduce 模式:

implicit class MapReduceTraversable[T, N](val traversable: Traversable[(T, N)]) {
  def reduceByKey(f: (N, N) => N) = traversable.par.groupBy(_._1).mapValues(_.map(_._2)).mapValues(_.reduce(f))
}

val fruits = List("apple", "apple", "orange", "apple", "mango", "orange", "apple", "apple", "apple", "apple") 

fruits.map(f => (f,1)).reduceByKey(_ + _)

res2: collection.parallel.ParMap[String, Int] = ParMap(orange -> 2, mango -> 1, apple -> 7)

你可以像以前一样调试它:

fruits.map(f => (f,1)).reduceByKey{(a,b) => println(s"$a+$b=${a+b}"); a + b} 

1+1=2
1+1=2
2+1=3
3+1=4
4+1=5
5+1=6
6+1=7
res9: Map[String, Int] = Map("mango" -> 1, "orange" -> 2, "apple" -> 7)

【讨论】:

    【解决方案3】:

    不,没有这样的内置函数。您可以使用mapValues 而不是第二个map 来简化一点,但没有类似的foldValues。

    【讨论】:

      猜你喜欢
      • 2015-12-07
      • 2018-12-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-09
      • 2020-05-13
      • 2015-04-01
      • 2020-10-05
      • 1970-01-01
      相关资源
      最近更新 更多