2015-02-27 5 views
10

Я попытался использовать Map.map для преобразования карты в список кортежей. Однако это не удается. Я сделал следующие эксперименты:Scala: на карте Карта на список кортежей

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)) 

Обратите внимание, как создается список для отдельных элементов (R1), но карта производится для кортежей (r3). Даже не заставляя обрабатываемый тип (r2). Только явный вызов Seq сделал это (r4). Итак, мой вопрос: почему/как MapMap «автоматически» создает новую карту, а не список, например? Фактически, как определяется тип возврата (Seq, List и т. Д.)

+6

Что не так с 'm.toList'? Также обратите внимание, что отображение в коллекции возвращает другую коллекцию того же типа, поэтому вы действительно не можете вернуть отображение списка на «Карта», если вы не назовете «.toList» на нем. –

+0

@Ende - Ничего нехорошо. См. Комментарий ниже. – user2051561

ответ

14

A Map - это набор кортежей уже.

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

Когда вы отображения Map, вы отображения пары (ключ, значение), что она содержит. Это не может работать, потому что вы удаляете ключи и сохраняете только значения. Так что то, что у вас есть больше не Map, но шаг или два вверх по иерархии коллекции, Iterable:

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

Принуждения типа не может работать, потому что Map[A, B] не List[(A, B)]. Это эквивалент m.map(identity). Обратите внимание на то, как вы даже доступ к e с кортежами аксессорами:

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

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

Здесь Seq более обобщенно, чем List:

val r4 = m.toSeq 

простое решением, как указано на @EndeNeu является просто использовать toList. Когда вы получите map, он должен вернуть исходный тип коллекции, если это возможно. Поэтому сопоставление Map должно вернуть еще один Map, если только базовая структура не сделала его Map (например, полностью удаляет ключи) в r1.

+0

Спасибо m-z. Мой вопрос действительно: в случае 'r1', как« Карта »знает, что он должен преобразовать в« Список »? Это могло быть что-то еще? Почему не массив? Я предполагаю, что здесь происходит некоторое неявное преобразование. Следовательно, мое тестирование, заставляя типы. Что касается кортежей, имеет смысл. Это соглашение о карте. – user2051561

+0

@ user2051561 Он не преобразует его в 'List' в' r1' - он возвращает 'Iterable', потому что это следующий ближайший признак иерархии, соответствующий типу вашей коллекции. 'Карта' расширяет' Iterable'. –