2009-07-30 12 views
8

(Questa è una variante a this Q&A)Scala il modo migliore per trasformare una raccolta in una mappa per chiave? (2 ° variante)

Dire che ho questo:

List("foo", "bar", "spam") 

voglio creare una mappa per il quale la chiave è la lunghezza della stringa e il valore è una raccolta di tutte le stringhe che hanno quella lunghezza. In altre parole, dato l'elenco su, otterremmo:

Map(3 -> List(foo, bar), 4 -> List(spam)) 

Il codice che ho scritto per fare questo è:

list.foldLeft(Map[Long, List[String]]()) { 
    (m, s) => m(s.length) = s :: 
    (if (m.contains(s.length)) m(s.length) 
     else Nil) 
} 

Questo funziona, ma aggiunge un sacco di bruttezza a l'elegante risposta fornita da Daniel Spiewak alla domanda originale (di cui sopra).

Qualche idea su come migliorare la soluzione per la mia variante?

Grazie! Sean

risposta

7

Se non ti dispiace prestazioni schifoso:

val list = List("foo", "bar", "spam") 
val keyValue = for (length <- list map (_ length) removeDuplicates; 
        strings = list filter (_.length == length)) 
       yield (length -> strings) 
val map = Map(keyValue: _*) 

Il problema è che l'elenco viene letto di nuovo per ogni lunghezza diversa.

Ora, circa l'uglyness della versione, forse questo aiuta:

list.foldLeft(Map[Long, List[String]]()) { 
    (m, s) => m(s.length) = s :: m.getOrElse(s.length, Nil) 
} 

meglio? Non è ancora abbastanza buono perché ottieni la lunghezza due volte. Questo non ha questo problema, ma è un po 'più brutta:

list.foldLeft(Map[Long, List[String]]()) { 
    (m, s) => val length = s.length; m(length) = s :: m.getOrElse(length, Nil) 
} 
+0

Non riesco a trovare l'ultima variante brutta, se la lunghezza della val è abbreviata in val l. Le variabili a lettera singola in scala sono spesso usate in scala in stile simile a formule matematiche, cioè dichiarate il significato di una variabile segnaposto e quindi semplicemente la usate. Poiché ciò porta a espressioni molto brevi (il più delle volte un liner), il nome breve che sarebbe considerato criptico in altre lingue non è un problema nella pratica. – Palimondo

+0

@Palimondo Non è la lunghezza che mi infastidisce. Non mi piace rompere il calcolo in due dichiarazioni. Sfortunatamente, Scala non può ottimizzare 's.length' per riutilizzare il valore, come farebbe Haskell. –

19

Con Scala 2.8.0:

list.groupBy(_.length) 

Non può essere più semplice di così!

+0

Penso che sia molto elegante, ma non capisco perché sia ​​necessario. Puoi spiegarlo? Grazie. – agilefall

+1

@agilefall: hai ragione. l'ordinamento non è necessario. Grazie! –