2015-02-27 19 views
10

Próbowałem użyć mapy Map.map, aby przekonwertować mapę na listę krotek. Jednak to się nie udaje. Zrobiłem następujące eksperymenty:Scala: zamapuj mapę na listę krotek

val m = Map(("a" -> 1), ("b" -> 2)) 
     //> m :  scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2) 
val r1 = m.map{ case (k,v) => v}    //> r1 : scala.collection.immutable.Iterable[Int] = List(1, 2) 
def toTuple[A,B](a:A,b:B) = (a,b)    //> toTuple: [A, B](a: A, b: B)(A, B) 
//val r2: List[Tuple2[_,_]] = m.map(e => (e._1,e._2)) 
val r3 = m.map(e => toTuple(e._1,e._2))   //> r3 : scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2) 
val r4 = m.toSeq        //> r4 : Seq[(String, Int)] = ArrayBuffer((a,1), (b,2)) 

zauważyć, jak lista jest generowany dla pojedynczych elementów (R1), ale mapa jest produkowany przez krotki (R3). Nawet wymuszenie działania nie zadziałało (r2). Wywołało to tylko jednoznaczne wywołanie Seq (r4) Więc moje pytanie brzmi: dlaczego/w jaki sposób Map.map "automagicznie" tworzy nową mapę, a nie na przykład listę? W rzeczywistości, w jaki sposób określono typ zwrotu (Seq, List, itp.)

+6

Co jest nie tak z 'm.toList'? Zwróć też uwagę, że mapowanie w kolekcji zwraca inną kolekcję tego samego typu, więc nie możesz odwzajemnić odwzorowania listy na 'Mapie', chyba że wywołasz na niej' .toList'. –

+0

@Ende - Nic nie jest nie tak. Zobacz komentarz poniżej. – user2051561

Odpowiedz

14

A Map to zbiór krotek już.

scala> "b" -> 2 
res0: (String, Int) = (b,2) // Implicitly converted to a Tuple 

Podczas mapowania Map, jesteś mapowanie (klucz, wartość) pary, które zawiera. To nie może działać, ponieważ rozbierasz klucze i zachowujesz tylko wartości. Więc co masz nie jest już Map, ale o krok lub dwa w górę hierarchii zbiórki Iterable:

val r1 = m.map{ case (k,v) => v} 

Wymuszenie typu nie może pracować, ponieważ Map[A, B] nie jest List[(A, B)]. Jest to odpowiednik m.map(identity). Zauważ, jak masz jeszcze dostępu e z akcesorów krotka:

val r2: List[Tuple2[_,_]] = m.map(e => (e._1,e._2)) 

val r3 = m.map(e => toTuple(e._1,e._2)) 

Tutaj Seq jest bardziej uogólniony niż List:

val r4 = m.toSeq 

Proste rozwiązanie jak stwierdził @EndeNeu jest po prostu użyć toList. Gdy kolekcja jest zbiorem map, powinna zwrócić oryginalny typ kolekcji, jeśli może. Tak więc odwzorowanie Map powinno zwrócić następną wartość: Map, chyba że podstawowa struktura spowodowała, że ​​nie jest już ona Map (tak jak usuwanie kluczy całkowicie) w r1.

+0

Dzięki m-z. Moje pytanie brzmi tak naprawdę: w przypadku 'r1', w jaki sposób' Map' wie, że powinien przekształcić się w 'List'? To mogło być coś innego? Dlaczego nie tablica? Zakładam, że są tu jakieś niejawne nawrócenia. Stąd moje testy przez zmuszanie typów. Co się tyczy krotek, ma sens. Taka jest konwencja mapy. – user2051561

+0

@ user2051561 Nie konwertuje go na 'List' w' r1' - zwraca 'Iterable', ponieważ jest to najbliższa właściwość w hierarchii, która pasuje do rodzaju kolekcji, którą posiadasz. 'Map' rozszerza' Iterable'. –