2010-10-22 2 views
2

В основном я не являюсь поклонником Java/Scala, но, к сожалению, я вынужден использовать его для учебы. В любом случае мне дали задание:scala список объектов, используя groupBy со средним значением

Что такое программа, это список объектов, таких как: Mark(val name String, val style_mark Int, val other_mark Int).

Как я могу использовать groupBy для группировки меток по имени и получения среднего значения для style_mark и other_mark?

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

Любая помощь будет высоко оценен,

Пол

ответ

3

Как уже говорилось, мы может использовать groupBy, чтобы сгруппировать метки по имени. Теперь у нас есть Map, где каждый ключ является именем, а значение представляет собой список знаков с этим именем.

Теперь мы можем перебрать, что Map и заменить каждый ключ-значение пару с Mark-объектом, который имеет ключ, как его имя, и среднее значение style_mark с в списке, как его style_mark и среднее other_mark с в списке other_mark. Как это:

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))) 
} 
+0

Спасибо за ответ, я как бы понял. Обновленный мой вопрос с кодом, который я правильно знаю, но он дает мне ошибку 'error: not found: value Mark' at' Mark (kv._1, ... ' – PawelMysior

+0

@Pawel: Если' Mark' не является case class, вам нужно написать 'new Mark (bla, bla, bla)' вместо 'Mark (bla, bla, bla)'. – sepp2k

+0

@Pawel: Также обратите внимание, что значение 'меток' останется неизменным, так что вы должен печатать возвращаемое значение выражения, а не значение «меток». (Хотя проще проверить код в REPL, чем создать файл и запустить его, и в этом случае вы можете просто ввести выражение и увидеть его результат) – sepp2k

6

Просто пару моментов здесь:

  1. Вы можете использовать шаблон соответствия, чтобы избежать все, что утомительный _1, _2 материал, который приходит с кортежами.

  2. Подчеркивает в переменной/имена параметров являются Bad Thing ™, они уже используются слишком сильно в другом месте на языке

Так высказав, что:

UPDATE: заменить avg с avgOf, сокращение дублирования :)

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

В реак l world, я бы, вероятно, сутенеру Traversable, чтобы добавить метод avgOf, чтобы вы могли написать v.avgOf(_.styleMark), но это просто усложнило бы этот пример.

+1

Должен быть 'case' перед' (k, v) '. – missingfaktor

+0

Не был бы я впервые ошибся в этой ошибке :) –

Смежные вопросы