List scala对象列表,使用groupBy和average

List scala对象列表,使用groupBy和average,list,scala,group-by,List,Scala,Group By,基本上,我不是一个真正的Java/Scala爱好者,但不幸的是,我不得不在学习中使用它。不管怎样,我被分配了一个任务: 程序得到的是一个对象列表,如:Mark(val-name-String,val-style\u-Mark-Int,val-other\u-Mark-Int) 如何使用groupBy按名称对标记进行分组,并获得样式标记和其他标记的平均值 Mark("John", 2, 5) Mark("Peter", 3, 7) Mark("John", 4, 3) 应返回: Mark("Jo

基本上,我不是一个真正的Java/Scala爱好者,但不幸的是,我不得不在学习中使用它。不管怎样,我被分配了一个任务:

程序得到的是一个对象列表,如:
Mark(val-name-String,val-style\u-Mark-Int,val-other\u-Mark-Int)

如何使用groupBy按名称对标记进行分组,并获得样式标记和其他标记的平均值

Mark("John", 2, 5)
Mark("Peter", 3, 7)
Mark("John", 4, 3)
应返回:

Mark("John", 3, 4)
Mark("Peter", 3, 7)
这就是代码:

class Mark(val name: String, val style_mark: Int, val other_mark: Int) {}

object Test extends Application
  {
  val m1 = new Mark("Smith", 18, 16);
  val m2 = new Mark("Cole", 14, 7);
  val m3 = new Mark("James", 13, 15);
  val m4 = new Mark("Jones", 14, 16);
  val m5 = new Mark("Richardson", 20, 19);
  val m6 = new Mark("James", 4, 18);

  val marks = List(m1, m2, m3, m4, m5, m6);

  def avg(xs: List[Int]) = xs.sum / xs.length

  marks.groupBy(_.name).map { kv => Mark(kv._1, avg(kv._2.map(_.style_mark)), avg(kv._2.map(_.other_mark))) }

  println(marks);
  }
任何帮助都将不胜感激


Paul

正如您所说,我们可以使用
groupBy
按名称对标记进行分组。现在我们有了一个
映射
,其中每个键都是名称,值是具有该名称的标记列表

现在,我们可以迭代该
映射
,并用一个标记对象替换每个键值对,该标记对象的名称为键,列表中
样式标记
s的平均值为其
样式标记
,列表中
其他标记
s的平均值为其
其他标记
。像这样:

def avg(xs: List[Int]) = xs.sum / xs.length
marks.groupBy(_.name).map { kv =>
  Mark(kv._1, avg(kv._2.map(_.style_mark)), avg(kv._2.map(_.other_mark)))
}

这里只有几点:

  • 您可以使用模式匹配来避免元组带来的所有单调乏味的东西

  • 变量/参数名称中的下划线是一件坏事™, 它们在语言的其他地方已经被大量使用了

  • 因此,声明:

    更新:
    avg
    替换为
    avgOf
    ,减少重复:)


    在现实世界中,我可能希望pimp Traversable添加
    avgOf
    方法,这样您就可以编写
    v.avgOf(uu.styleMark)
    ,但这只会使这个示例变得复杂。

    谢谢您的回答,我有点明白了。用我知道的代码更新了我的问题,但它给了我一个错误
    错误:未找到:值标记
    标记(kv._1,…
    @Pawel:如果
    标记
    不是case类,你需要编写
    新标记(bla,bla,bla)
    而不是
    标记(bla,bla,bla)
    @Pawel:还要注意,
    标记的值将保持不变,因此您应该打印表达式的返回值,而不是
    标记的值(尽管在REPL中测试代码比创建文件并运行它更容易,在这种情况下,您只需输入表达式并查看其结果).在
    (k,v)
    之前应该有
    案例
    。这也不是我第一次犯这样的错误:)
    //Needs two param lists so that inference will work properly
    //when supplying the closure
    def avgOf[T](xs:List[T])(f:(T)=>Int) = xs.map(f).sum / xs.length
    
    marks.groupBy(_.name).map {
      case (k,v) => new Mark(k, avgOf(v)(_.styleMark), avgOf(v)(_.otherMark))
    }