острота гистограммы Python

Существует много способов записать программу 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 функция (R.I.P).:

>>> 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(), но это - hypothethical, так как существует нет reduce там.)

Победите меня лучшим, большим количеством читаемой остроты!;)

47
задан argentpepper 16 October 2013 в 20:51
поделиться

3 ответа

Python 3.x действительно имеет reduce , вам просто нужно сделать из functools import reduce . У него также есть «понимание слов», синтаксис которых точно такой же, как в вашем примере.

Python 2.7 и 3.x также имеют класс Counter , который делает именно то, что вы хотите:

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

В Python 2.6 или более ранних версиях я бы лично использовал defaultdict и сделайте это в 2 строчки:

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

Это чисто, эффективно, на питоническом языке и намного проще для понимания, чем что-либо, связанное с reduce .

76
ответ дан 26 November 2019 в 19:29
поделиться

Какое-то время все, что использует 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.

1
ответ дан 26 November 2019 в 19:29
поделиться

Импортировать модули для oneliner'ов вроде бы хитро, так что вот однострочный O (n), работающий, по крайней мере, еще в Python2.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}

:)

7
ответ дан 26 November 2019 в 19:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: