有很多方法可以编写计算直方图的Python程序。

通过直方图,我的意思是计算对象在一个中的发生的函数 iterable 并输出字典中的计数。例如:

>>> L = 'abracadabra'
>>> histogram(L)
{'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}

编写此功能的一种方法是:

def histogram(L):
    d = {}
    for x in L:
        if x in d:
            d[x] += 1
        else:
            d[x] = 1
    return d

还有更多简洁的方法来编写此功能吗?

如果我们在Python中具有字典综合,我们可以写信:

>>> { x: L.count(x) for x in set(L) }

但是由于Python 2.6没有它们,我们必须写下:

>>> dict([(x, L.count(x)) for x in set(L)])

尽管这种方法可能是可读的,但它不高,l通过多次行走。此外,这对单人生发电机不起作用。该功能应适用于迭代器生成器,例如:

def gen(L):
    for x in L:
        yield x

我们可能会尝试使用 reduce 功能(RIP):

>>> reduce(lambda d,x: dict(d, x=d.get(x,0)+1), L, {}) # wrong!

糟糕,这不起作用:关键名称是 'x', , 不是 x. :(

我以:

>>> reduce(lambda d,x: dict(d.items() + [(x, d.get(x, 0)+1)]), L, {})

(在Python 3中,我们必须写 list(d.items()) 代替 d.items(), ,但这是假想的,因为没有 reduce 那里。)

请用更好,更可读的单线击败我! )

有帮助吗?

解决方案

Python 3.x确实有 reduce, ,您只需要做一个 from functools import reduce. 。它还具有“ dict enlastions”,在您的示例中完全具有语法。

Python 2.7和3.x也有一个 柜台 班级完全可以做您想要的:

from collections import Counter
cnt = Counter("abracadabra")

在Python 2.6或更早之前,我个人会使用 默认值 并以2行进行操作:

d = defaultdict(int)
for x in xs: d[x] += 1

这是干净,高效,pythonic,并且让大多数人比涉及任何内容更容易理解 reduce.

其他提示

进口模块是有点欺骗,所以这是一个Oneliner,是O(n),至少可以追溯到Python2.42.4

>>> f=lambda s,d={}:([d.__setitem__(i,d.get(i,0)+1) for i in s],d)[-1]
>>> f("ABRACADABRA")
{'A': 5, 'R': 2, 'B': 2, 'C': 1, 'D': 1}

如果您认为 __ 方法是黑客,您可以随时执行此操作

>>> f=lambda s,d=lambda:0:vars(([setattr(d,i,getattr(d,i,0)+1) for i in s],d)[-1])
>>> f("ABRACADABRA")
{'A': 5, 'R': 2, 'B': 2, 'C': 1, 'D': 1}

:)

$d{$_} += 1 for split //, 'abracadabra';
import pandas as pd

pd.Series(list(L)).value_counts()

对于Python 2.7,您可以使用此小列表理解:

v = list('abracadabra')
print {x: v.count(x) for x in set(v)}

一个可以追溯到2.3(比Timmerman的稍短,我认为更可读):

L = 'abracadabra'
hist = {}
for x in L: hist[x] = hist.pop(x,0) + 1
print hist
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}

一会儿,任何使用的东西 itertools 从定义上讲是Pythonic。尽管如此,这在不透明的一面还是有点

>>> from itertools import groupby
>>> grouplen = lambda grp : sum(1 for i in grp)
>>> hist = dict((a[0], grouplen(a[1])) for a in groupby(sorted("ABRACADABRA")))
>>> print hist
{'A': 5, 'R': 2, 'C': 1, 'B': 2, 'D': 1}

我目前正在运行Python 2.5.4。

您的单线使用 reduce 几乎可以,您只需要对其进行一些调整:

>>> reduce(lambda d, x: dict(d, **{x: d.get(x, 0) + 1}), L, {})
{'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}

当然,这不会击败就地解决方案(也没有速度,也不会以pythonicity为单位),但是作为交换,您拥有一个纯粹的功能性片段。顺便说一句,如果Python有一种方法,这会更漂亮 dict.merge().

我需要一个直方图实施才能在Python 2.2上运行2.7,并提出了这一点:

>>> L = 'abracadabra'
>>> hist = {}
>>> for x in L: hist[x] = hist.setdefault(x,0)+1
>>> print hist
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}

我受到埃利·法院(Eli Courtwright)在违约行为的帖子的启发。这些是在Python 2.5中引入的,因此无法使用。但是可以使用dict.setDefault(键,默认)模拟它们。

这基本上是Gnibbler所做的同一件事,但是我必须先写这篇文章,然后才能完全理解他的lambda功能。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top