2016-05-16 2 views
0

С Python, я могу сделать что-то вродеКак мне понять карту с помощью Scala?

listOfLists = [('a', -1), ('b', 0), ('c', 1)] 
my_dict = {foo: bar for foo, bar in listOfLists} 

my_dict == {'a': -1, 'b': 0, 'c': 1} => True 

Я знаю, что это как словарь понимания. Когда я ищу эту операцию со Скалой, я нахожу this incomprehensible document (каламбур предназначен).

Есть ли идиоматический способ сделать это с помощью Scala?

Вопрос с бонусом: Могу ли я фильтровать эту операцию, как my_dict = {foo: bar for foo, bar in listOfLists if bar > 0}?

+0

Каков тип 'listOfLists'? – sjrd

+3

Было бы полезно включить ожидаемый ввод и вывод, фрагмент кода, который вы опубликовали, действительно загадочен для меня. –

+0

@sjrd Скажите, что это список [Список [Объект]] – munk

ответ

5

Прежде всего, давайте проанализируем ваш код Python, чтобы выяснить, что он делает.

my_dict = { 
    foo: bar  <-- Key, value names 
    for foo, bar <-- Destructuring a list 
    in listOfLists <-- This is where they came from 
} 

Таким образом, вы можете видеть, что даже в этом очень короткий пример есть на самом деле значительная избыточность и большой потенциал для отказа, если listOfLists это на самом деле не то, что он говорит, что это.

Если listOfLists на самом деле это список пар (ключ, значение), то в Scala это тривиальное:

listOfPairs.toMap 

Если, с другой стороны, это на самом деле списки, и вы хотите, чтобы стянуть первый один, чтобы сделать ключ и сохранить остальное в качестве значения, это будет что-то вроде

listOfLists.map(x => x.head -> x.tail).toMap 

Вы можете выбрать некоторые из них с помощью collect вместо этого. Например, может быть, вы хотите только списки длины 2 (вы могли бы if x.head > 0, чтобы получить ваш пример), в этом случае вам

listOfLists.collect{ 
    case x if x.length == 2 => x.head -> x.last 
}.toMap 

или, если это буквально List, вы можете также

listOfLists.collect{ 
    case key :: value :: Nil => key -> value 
}.toMap 
3

Вот несколько примеров:

val listOfLists = Vector(Vector(1,2), Vector(3,4), Vector(5,6)) 

val m1 = listOfLists.map { case Seq(a,b) => (a,b) }.toMap 
val m2 = listOfLists.collect { case Seq(a,b) if b>0 => (a,b) }.toMap 
val m3 = (for (Seq(a,b) <- listOfLists) yield (a,b)).toMap 
val m4 = (for (Seq(a,b) <- listOfLists if b>0) yield (a,b)).toMap 

val m5 = Map(listOfLists.map { case Seq(a,b) => (a,b) }: _*) 
val m6 = Map(listOfLists.collect { case Seq(a,b) => (a,b) }: _*) 
val m7 = Map((for (Seq(a,b) <- listOfLists) yield (a,b)): _*) 
val m8 = Map((for (Seq(a,b) <- listOfLists if b>0) yield (a,b)): _*) 

Вы можете создать Map с помощью .toMap или Map(xs: _*). Метод collect позволяет фильтровать, как вы map. И для понимания используется синтаксис, наиболее похожий на ваш пример.

1

Я сравню list comprehension в Scala2.x и Python 3.x

1. Последовательность

В питона:

xs = [x*x for x in range(5)] 
#xs = [0, 1, 4, 9, 16] 

ys = list(map(lambda x: x*x, range(5))) 
#ys = [0, 1, 4, 9, 16] 

В Scala:

scala> val xs = for(x <- 0 until 5) yield x*x 
xs: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4, 9, 16) 

scala> val ys = (0 until 5) map (x => x*x) 
ys: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4, 9, 16) 

Или вы действительно хотите список:

scala> import collection.breakOut 

scala> val xs: List[Int] = (for(x <- 0 until 5) yield x*x)(breakOut) 
xs: List[Int] = List(0, 1, 4, 9, 16) 

scala> val ys: List[Int] = (0 until 5).map(x => x*x)(breakOut) 
ys: List[Int] = List(0, 1, 4, 9, 16) 

scala> val zs = (for(x <- 0 until 5) yield x*x).toList 
zs: List[Int] = List(0, 1, 4, 9, 16) 

2.Набор

В Python

s1 = { x//2 for x in range(10) } 
#s1 = {0, 1, 2, 3, 4} 
s2 = set(map(lambda x: x//2, range(10))) 
#s2 = {0, 1, 2, 3, 4} 

В Scala

scala> val s1 = (for(x <- 0 until 10) yield x/2).toSet 
s1: scala.collection.immutable.Set[Int] = Set(0, 1, 2, 3, 4) 

scala> val s2: Set[Int] = (for(x <- 0 until 10) yield x/2)(breakOut) 
s2: Set[Int] = Set(0, 1, 2, 3, 4) 

scala> val s3: Set[Int] = (0 until 10).map(_/2)(breakOut) 
s3: Set[Int] = Set(0, 1, 2, 3, 4) 

scala> val s4 = (0 until 10).map(_/2).toSet 
s4: scala.collection.immutable.Set[Int] = Set(0, 1, 2, 3, 4) 

3. Dict

В Python:

pairs = [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')] 
#d1 = {1: 'aa', 2: 'bb', 3: 'cc', 4: 'dd'} 

d2 = dict([(k*2, v) for k, v in pairs]) 
#d2 = {2: 'a', 4: 'b', 6: 'c', 8: 'd'} 

В Scala

scala> val pairs = Seq(1->"a", 2->"b", 3->"c", 4->"d") 
pairs: Seq[(Int, String)] = List((1,a), (2,b), (3,c), (4,d)) 

scala> val d1 = (for((k, v) <- pairs) yield (k, v*2)).toMap 
d1: scala.collection.immutable.Map[Int,String] = Map(1 -> aa, 2 -> bb, 3 -> cc, 4 -> dd) 

scala> val d2 = Map(pairs map { case(k, v) => (k*2, v) } :_*) 
d2: scala.collection.immutable.Map[Int,String] = Map(2 -> a, 4 -> b, 6 -> c, 8 -> d) 

scala> val d3 = pairs map { case(k, v) => (k*2, v) } toMap 
d3: scala.collection.immutable.Map[Int,String] = Map(2 -> a, 4 -> b, 6 -> c, 8 -> d) 

scala> val d4: Map[Int, String] = (for((k, v) <- pairs) yield (k, v*2))(breakOut) 
d4: Map[Int,String] = Map(1 -> aa, 2 -> bb, 3 -> cc, 4 -> dd) 
Смежные вопросы