如何在python中减少元组列表

如何在python中减少元组列表,python,python-2.7,mapreduce,Python,Python 2.7,Mapreduce,我有一个数组,我想计算数组中每个项目的出现次数 我已经设法使用map函数来生成元组列表 def mapper(a): return (a, 1) r = list(map(lambda a: mapper(a), arr)); //output example: //(11817685, 1), (2014036792, 1), (2014047115, 1), (11817685, 1) 我希望reduce函数可以帮助我按照每个元组中的第一个数字(id)对计数进行分组。例如:

我有一个数组,我想计算数组中每个项目的出现次数

我已经设法使用map函数来生成元组列表

def mapper(a):
    return (a, 1)

r = list(map(lambda a: mapper(a), arr));

//output example: 
//(11817685, 1), (2014036792, 1), (2014047115, 1), (11817685, 1)
我希望reduce函数可以帮助我按照每个元组中的第一个数字(id)对计数进行分组。例如:

(11817685, 2), (2014036792, 1), (2014047115, 1)
我试过了

cnt = reduce(lambda a, b: a + b, r);
还有其他一些方法,但它们都不起作用

注意
感谢所有关于解决问题的其他方法的建议,但我只是在这里学习Python和如何实现map reduce,我已经简化了我的实际业务问题,使其易于理解,因此请向我展示一种正确的map reduce方法

您可以使用
计数器

from collections import Counter
arr = [11817685, 2014036792, 2014047115, 11817685]
counter = Counter(arr)
print zip(counter.keys(), counter.values())
编辑:

正如@ShadowRanger
计数器所指出的那样,计数器具有
项()
方法:

from collections import Counter
arr = [11817685, 2014036792, 2014047115, 11817685]
print Counter(arr).items()

如果您只需要
cnt
,那么
dict
可能比
元组的
列表
更好(如果您需要这种格式,只需使用
dict.items

collections
模块为此提供了一个有用的数据结构,即
defaultdict

from collections import defaultdict
cnt = defaultdict(int) # create a default dict where the default value is
                       # the result of calling int
for key in arr:
  cnt[key] += 1 # if key is not in cnt, it will put in the default

# cnt_list = list(cnt.items())

不使用任何外部模块,您可以使用一些逻辑,不使用任何模块:

track={}
if intr not in track:
    track[intr]=1
else:
    track[intr]+=1
示例代码:

对于这些类型的列表问题,有一种模式:

因此,假设您有一个列表:

a=[(2006,1),(2007,4),(2008,9),(2006,5)]
您希望将其转换为dict,作为元组的第一个元素,作为键,作为元组的第二个元素。比如:

{2008: [9], 2006: [5], 2007: [4]}
但有一个陷阱,您也希望那些具有不同值但键相同的键,如(2006,1)和(2006,5)键相同但值不同。您希望这些值仅附加一个键,以便获得预期的输出:

{2008: [9], 2006: [1, 5], 2007: [4]}
对于这类问题,我们采取如下措施:

首先创建一个新的dict,然后我们遵循以下模式:

if item[0] not in new_dict:
    new_dict[item[0]]=[item[1]]
else:
    new_dict[item[0]].append(item[1])
因此,我们首先检查key是否在new dict中,如果它已经存在,则将duplicate key的值添加到其值中:

完整代码:

a=[(2006,1),(2007,4),(2008,9),(2006,5)]

new_dict={}

for item in a:
    if item[0] not in new_dict:
        new_dict[item[0]]=[item[1]]
    else:
        new_dict[item[0]].append(item[1])

print(new_dict)
输出:

{2008: [9], 2006: [1, 5], 2007: [4]}
写信给之后,我想起了这篇文章,并认为在这里写一个类似的答案会有所帮助

下面是一种在列表中使用
reduce
以获得所需输出的方法

arr = [11817685, 2014036792, 2014047115, 11817685]

def mapper(a):
    return (a, 1)

def reducer(x, y):
    if isinstance(x, dict):
        ykey, yval = y
        if ykey not in x:
            x[ykey] = yval
        else:
            x[ykey] += yval
        return x
    else:
        xkey, xval = x
        ykey, yval = y
        a = {xkey: xval}
        if ykey in a:
            a[ykey] += yval
        else:
            a[ykey] = yval
        return a

mapred = reduce(reducer, map(mapper, arr))

print mapred.items()
其中打印:

[(2014036792, 1), (2014047115, 1), (11817685, 2)]

有关更详细的说明,请参见。

lambda:mapper(a)
?为什么不直接通过
mapper
?另外:您的预期输出是什么?谢谢您的评论。是的,我可以直接通过mapper,我正在试验其他东西。已添加我的预期输出。您需要
r
还是它只是一个中介?只是一个中介。无论
reduce
还是
map
都不能真正帮助您。这类任务就是存在
collections.Counter
的原因(对于输入已经排序的更特殊的情况,
itertools.groupby
)。Map/Reduce策略适用于多个映射器并行输入多个还原器的情况;盲目地将相同的模式应用于纯单线程代码是浪费的(在Map/Reduce情况下也是浪费的,你只需要依靠荒谬的并行级别来弥补开销)。为什么
zip
键和
值?有一种直接执行此操作的
items
方法:
print counter.items()
,还有一种特殊用途的方法
most\u common
,它按频率顺序显示结果(对结果数量有可选限制),例如
print counter.most\u common()