Я хотел бы сгруппировать последовательность в карту последовательностей, основанную на дискриминаторе типа Option
, аналогичном результату метода groupBy
, но где значения, приводящие к None
, отбрасываются.Или, возможно, группировка по PartialFunction
дискриминатору и отбрасывание тех, для которых не определена частичная функция.
Вот конкретный пример:
У меня есть коллекция имен и коллекцияпространств имен.Некоторые, но не все, имена принадлежат допустимому пространству имен, и я хочу сгруппировать те, которые делают, в Карту, отбрасывая те, которые не делают.
В настоящее время мое решение эквивалентно:
val names = List("ns1.foo", "ns2.bar", "ns2.baz", "froznit")
val namespaces = List("ns1", "ns2")
def findNamespace(n: String): Option[String] = namespaces.find(n.startsWith)
val groupedNames = names.groupBy(findNamespace).collect {
case (Some(ns), name) => (ns, name)
}
// Map((ns1,List(ns1.foo)), (ns2,List(ns2.bar, ns2.baz)))
Мое беспокойство по поводу этого решения состоит в том, что, используя names.groupBy(findNamespace)
, я создаю промежуточную Карту, которая содержит все имена, которые меня не интересуют, под ключом None
.Если количество имен, от которых я отказываюсь, становится большим, это решение становится менее привлекательным.
Моя попытка избежать этого - нечто вроде крушения поезда, хотя:
val groupedNames =
names.
map(n => (findNamespace(n), n)).
collect({ case (Some(ns), n) => (ns, n) }).
groupBy(_._1).
map({ case (ns, names) => (ns, names.map(_._2)) })
Если бы вырешить это более умным способом, что бы это было?
Редактировать: в идеале решение должно вызывать findNamespace(name)
только один раз для каждого имени и строить Карту, используя только значения Option[String]
,без вызова отдельного предиката hasNamespace(name)
.