Обработка набора множеств и возврат плоского итерируемого - PullRequest
5 голосов
/ 20 января 2011
val input=Set(Set("a","b"),Set("b","c"))

Я хочу это:

Map("a"->1,"b"->2,"c"->1)

Каков наилучший функциональный подход для реализации такой функциональности? Использование ключевого слова yield приводит к вложенным итерациям:

output = for(firstlevel<-input) yield for(item<-firstlevel) yield item

Ответы [ 3 ]

8 голосов
/ 20 января 2011

обновление: включает предложение использовать input.toSeq.flatten
вместо input.toSeq flatMap { _.toSeq }

преобразовать в одну последовательность значений ...

input.toSeq.flatten

... групповые значения, которые соответствуют ...

input.toSeq.flatten groupBy { identity }

... и считать

input.toSeq.flatten groupBy { identity } mapValues { _.size }
2 голосов
/ 20 января 2011

Если вы хотите использовать для понимания и доходности:

<code>output = for{
    (set,idx) <- input.zipWithIndex
    item <- set
} yield (item -> idx)

Код в вашей последней строке можно упростить (но не то, что вы хотите):

<code>output = for{
    set <- input
    item <- set
} yield item
1 голос
/ 20 января 2011

О, мальчик, это так ужасно ...

input.foldLeft(Map[String,Int]())((m,s) => 
   s.foldLeft(m)((n,t) => n + (t -> (1 + n.getOrElse(t,0)))))

[Изменить]

API-интерфейсу Collection действительно нужен метод для "объединения" двух карт (или я просто пропустил это ???), например,

def merge[A,B](m1: Map[A,B], m2:Map[A,B])(f: (B,B)=>B):Map[A,B] =
  m1.foldLeft(m2)((m,t) =>
      m + (t._1 -> m.get(t._1).map(k => f(k,t._2)).getOrElse(t._2)))

С этим вы можете написать что-то вроде:

input.map(_.map(x => x -> 1).toMap).reduceLeft(merge(_,_)(_+_))

[Edit2]

С идеей Кевина слияние можно записать как

def merge[A,B](m1: Map[A,B], m2:Map[A,B])(f: (B,B)=>B):Map[A,B] =
   m1.keys ++ m2.keys map {k => k ->
        List(m1.get(k), m2.get(k)).flatten.reduceLeft(f)} toMap

Похоже, мой Скала-Фу все еще слишком слаб. Какой самый лучший способ выразить

(o1,o2) match {
    case (Some(x),Some(y)) => Some(f(x,y))    
    case (Some(x), _) => Some(x)    
    case (_, Some(y)) => Some(y)    
    case => error("crack in the time-space-continuum")  
}

...