让我们假设,我在Spark中有一个键值对,如下所示。
[ (Key1, Value1), (Key1, Value2), (Key1, Vaue3), (Key2, Value4), (Key2, Value5) ]
现在我想减少这个,就像这样。
[ (Key1, [Value1, Value2, Value3]), (Key2, [Value4, Value5]) ]
即,从Key-Value到Key-List of Values。
如何使用python或scala中的map和reduce函数来做到这一点?
答案 0 :(得分:4)
collections.defaultdict
可以是解决方案https://docs.python.org/2/library/collections.html#collections.defaultdict
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for key, value in [('Key1', 'Value1'), ('Key1', 'Value2'), ('Key1', 'Vaue3'), ('Key2', 'Value4'), ('Key2', 'Value5') ]:
... d[key].append(value)
>>> print d.items()
[('Key2', ['Value4', 'Value5']), ('Key1', [ 'Value1','Value2', 'Vaue3'])]
答案 1 :(得分:2)
val data = Seq(("Key1", "Value1"), ("Key1", "Value2"), ("Key1", "Vaue3"), ("Key2", "Value4"), ("Key2", "Value5"))
data
.groupBy(_._1)
.mapValues(_.map(_._2))
res0: scala.collection.immutable.Map[String,Seq[String]] =
Map(
Key2 -> List(Value4, Value5),
Key1 -> List(Value1, Value2, Vaue3))
答案 2 :(得分:1)
我确信有一种更易读的方法,但首先想到的是使用itertools.groupby
。按元组的第一个元素(键)对列表进行排序。然后使用列表推导来迭代组。
from itertools import groupby
l = [('key1', 1),('key1', 2),('key1', 3),('key2', 4),('key2', 5)]
l.sort(key = lambda i : i[0])
[(key, [i[1] for i in values]) for key, values in groupby(l, lambda i: i[0])]
输出
[('key1', [1, 2, 3]), ('key2', [4, 5])]
答案 3 :(得分:0)
像这样的东西
newlist = dict()
for x in l:
if x[0] not in newlist:
dict[x[0]] = list()
dict[x[0]].append(x[1])
答案 4 :(得分:0)
使用defaultdict的最短时间如下:没有要求排序。
>>> from collections import defaultdict
>>> collect = lambda tuplist: reduce(lambda acc, (k,v): acc[k].append(v) or acc,\
tuplist, defaultdict(list))
>>> collect( [(1,0), (2,0), (1,2), (2,3)])
defaultdict(<type 'list'>, {1: [0, 2], 2: [0, 3]})
答案 5 :(得分:0)
另一个scala,避免使用groupBy / mapValues(虽然这是明显的Scala解决方案,但这个解决方案遵循Vishni给出的python,因为@MetallicPriest评论说“更容易”)
val data = Seq(("Key1", "Value1"), ("Key1", "Value2"), ("Key1", "Vaue3"),
("Key2", "Value4"), ("Key2", "Value5"))
val dict = Map[String, Seq[String]]() withDefaultValue(Nil)
data.foldLeft(dict){ case (d, (k,v)) => d updated (k, d(k) :+ v) }
// Map(Key1 -> List(Value1, Value2, Vaue3), Key2 -> List(Value4, Value5))
(是否附加了密钥以提供问题的确切结果。但是,Prepend会更有效率)
可变版本,更接近Python版本:
import scala.collection.mutable.{Map, Seq}
val dict = Map[String, Seq[String]]() withDefaultValue(Seq())
for ((k,v) <- data) dict(k) :+= v
dict
// Map(Key2 -> ArrayBuffer(Value4, Value5),
// Key1 -> ArrayBuffer(Value1, Value2, Vaue3))