groupBy в поле класса case динамически в scala

Как я могу выполнить операцию groupBy для списка классов дел, имеющих классы дел в качестве полей? Например:

case class F1(str1:Option[String],str2:Option[String])
case class F2(int1:Option[Int],int2:Option[Int])

case class Parent(str:F1, int:F2)

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

val data = List(Parent(F1(Some("abc"), Some("pqr"))), F2(Some(20), Some(30)))
                Parent(F1(Some("abc"), Some("xyz"))), F2(Some(20), Some(30)))
                Parent(F1(Some("def"), Some("pqr"))), F2(None, Some(30)))
                Parent(F1(Some("def"), Some("pqr"))), F2(Some(20), Some(30)))
                Parent(F1(None, Some("xyz"))), F2(None, Some(30))))

Я хочу выполнить data.groupBy("str1"), где «str1» — это имя поля case calss F1, которое будет передаваться динамически.

Если эта операция выполнена успешно, вывод будет таким:

Map(Some("abc") -> List(Parent(F1(Some("abc"), Some("pqr"))), F2(Some(20), Some(30))),
                        Parent(F1(Some("abc"), Some("xyz"))), F2(Some(20), Some(30)))),
    Some("def") -> List(Parent(F1(Some("def"), Some("pqr"))), F2(None, Some(30))),
                        Parent(F1(Some("def"), Some("pqr"))), F2(Some(20), Some(30)))),
    None        -> List(Parent(F1(None, Some("xyz"))), F2(None, Some(30))))) 

person KishanS    schedule 15.07.2018    source источник


Ответы (1)


для List[+A] у groupBy есть подпись

def groupBy[K](f: (A) ⇒ K): Map[K, List[A]]

Для вас A — это Parent, поэтому вы можете использовать

data.groupBy(_.str.str1)

Здесь .str сопоставляется с F1, затем .str1 сопоставляется с Option[String], по которому вы хотите сгруппировать.

В частности, мы передаем A => K в groupBy, а не значение. Если вы пытались передать (что-то вроде) строку вместо этого, например. (_ => "str1") в groupBy, он сопоставит все с этой строкой во время группировки, поэтому все окажется в одной группе, и у вас будет просто Map("str1" -> data).

Что касается динамической передачи "str1", вы можете передать _.str.str1

person joel    schedule 15.07.2018
comment
Спасибо за ответы. Я хотел бы подробнее остановиться на ситуации. groupBy может выполняться для любого поля (str1, str2, int1 или int2), и это поле неизвестно во время компиляции, код будет иметь эту информацию только во время выполнения. Я могу придумать один из способов сделать это, используя сопоставление с образцом, например: case str1 => data.groupBy( _.str.str1); case str2 => data.groupBy( _.str.str2); . Есть ли другой способ сделать это? - person KishanS; 16.07.2018
comment
отражение должно уметь это делать, но я никогда не использовал его сам docs.scala-lang .org/overviews/reflection/overview.html - person joel; 16.07.2018
comment
тем не менее, если есть только четыре случая, я бы выбрал что-то вроде сопоставления с образцом - person joel; 16.07.2018