Scala najlepszym sposobem na przekształcenie kolekcji w Mapę po kluczu?
Jeśli mam zbiór c
typu T
i istnieje właściwość p
na T
(typu P
, powiedzmy), jaki jest najlepszy sposób na zrobienie map-by-extracting-key ?
val c: Collection[T]
val m: Map[P, T]
Jeden sposób jest następujący:
m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }
Ale teraz potrzebuję mutowalnej mapy. Czy jest lepszy sposób, aby zrobić to tak, że jest w 1 linii i kończy się niezmienna Mapa? (Oczywiście mógłbym zamienić powyższe w proste narzędzie biblioteczne, tak jak w Javie, ale podejrzewam, że w Scali nie ma potrzeby)
11 answers
Możesz użyć
c map (t => t.getP -> t) toMap
Ale należy pamiętać, że to wymaga 2 trawersy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-20 10:47:52
Możesz skonstruować mapę ze zmienną liczbą krotek. Użyj metody map na kolekcji, aby przekonwertować ją na kolekcję krotek, a następnie użyj sztuczki:_*, aby przekonwertować wynik na argument zmiennej.
scala> val list = List("this", "maps", "string", "to", "length") map {s => (s, s.length)}
list: List[(java.lang.String, Int)] = List((this,4), (maps,4), (string,6), (to,2), (length,6))
scala> val list = List("this", "is", "a", "bunch", "of", "strings")
list: List[java.lang.String] = List(this, is, a, bunch, of, strings)
scala> val string2Length = Map(list map {s => (s, s.length)} : _*)
string2Length: scala.collection.immutable.Map[java.lang.String,Int] = Map(strings -> 7, of -> 2, bunch -> 5, a -> 1, is -> 2, this -> 4)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-23 21:11:37
Oprócz rozwiązania @ James Iry, możliwe jest również osiągnięcie tego za pomocą fałdy. Podejrzewam, że to rozwiązanie jest nieco szybsze niż metoda tuple (powstaje mniej obiektów śmieci):
val list = List("this", "maps", "string", "to", "length")
val map = list.foldLeft(Map[String, Int]()) { (m, s) => m(s) = s.length }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-24 18:39:42
Można to zaimplementować niezmiennie i za pomocą pojedynczego przejścia przez zbiór w następujący sposób.
val map = c.foldLeft(Map[P, T]()) { (m, t) => m + (t.getP -> t) }
Rozwiązanie działa, ponieważ dodanie do niezmiennej Mapy zwraca nową niezmienną mapę z dodatkowym wpisem i ta wartość służy jako akumulator w operacji składania.
Kompromis polega tutaj na prostocie kodu a jego skuteczności. Tak więc w przypadku dużych zbiorów podejście to może być bardziej odpowiednie niż zastosowanie 2 implementacji takich jako zastosowanie map
i toMap
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-13 17:49:15
Inne rozwiązanie (może nie działać dla wszystkich typów)
import scala.collection.breakOut
val m:Map[P, T] = c.map(t => (t.getP, t))(breakOut)
Pozwala to uniknąć tworzenia listy pośredników, więcej informacji tutaj: Scala 2.8 breakOut
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:04
To, co próbujesz osiągnąć, jest trochę nieokreślone.
Co jeśli dwa lub więcej elementów c
mają ten sam p
? Który element zostanie zmapowany do p
na mapie?
Dokładniejszym sposobem patrzenia na to jest uzyskanie mapy pomiędzy p
A wszystkimi c
przedmiotami, które ją posiadają:
val m: Map[P, Collection[T]]
Można to łatwo osiągnąć dzięki groupBy :
val m: Map[P, Collection[T]] = c.groupBy(t => t.p)
Jeśli nadal chcesz oryginalną mapę, możesz na przykład mapować p
do pierwszej t
, która ma it:
val m: Map[P, T] = c.groupBy(t => t.p) map { case (p, ts) => p -> ts.head }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-03 16:37:54
c map (_.getP) zip c
Działa dobrze i jest bardzo intuicyjny
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-04 10:37:56
Jeśli to coś warte, oto dwa bezsensowne sposoby na zrobienie tego:
scala> case class Foo(bar: Int)
defined class Foo
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> val c = Vector(Foo(9), Foo(11))
c: scala.collection.immutable.Vector[Foo] = Vector(Foo(9), Foo(11))
scala> c.map(((_: Foo).bar) &&& identity).toMap
res30: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))
scala> c.map(((_: Foo).bar) >>= (Pair.apply[Int, Foo] _).curried).toMap
res31: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-04 10:07:23
To prawdopodobnie nie jest najskuteczniejszy sposób na przekształcenie listy w mapę, ale sprawia, że kod wywołujący jest bardziej czytelny. Użyłem niejawnych konwersji, aby dodać metodę mapBy do listy:
implicit def list2ListWithMapBy[T](list: List[T]): ListWithMapBy[T] = {
new ListWithMapBy(list)
}
class ListWithMapBy[V](list: List[V]){
def mapBy[K](keyFunc: V => K) = {
list.map(a => keyFunc(a) -> a).toMap
}
}
Przykład kodu wywołującego:
val list = List("A", "AA", "AAA")
list.mapBy(_.length) //Map(1 -> A, 2 -> AA, 3 -> AAA)
Zauważ, że ze względu na niejawną konwersję, kod wywołujący musi zaimportować niejawne konwersje Scali.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-27 06:22:49
To działa dla mnie:
val personsMap = persons.foldLeft(scala.collection.mutable.Map[Int, PersonDTO]()) {
(m, p) => m(p.id) = p; m
}
Mapa musi być zmienna i mapa musi być zwrócona, ponieważ dodanie do mapy zmiennej nie zwraca mapy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-30 21:14:56
Użyj map() na kolekcji, a następnie toMap
val map = list.map(e => (e, e.length)).toMap
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-24 11:40:05