Вопрос

Есть много способов написать программу 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. Отказ Он также имеет «обречье понятие», которые имеют именно синтаксис в вашем примере.

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

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

Другие советы

Это Cheda Chensy для импорта модулей для OnEliners, поэтому вот 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}

:)

$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 (немного короче Тиммермана, я думаю, что более читаемый):

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 был по определению питон. Тем не менее, это немного на непрозрачной стороне:

>>> 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}

Конечно, это не будет побеждать в месте решения (ни в скорости, ни в пиктоничности), но в обмен у вас есть приятный чисто функциональный фрагмент. Кстати, это было бы несколько красивее, если у Питона был метод 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}

Я был вдохновлен постом Эли Коррерайта по умолчанию. Они были введены в Python 2.5, так что нельзя использовать. Но они могут быть эмулированы с Dict.SetDefault (ключом, по умолчанию).

Это в основном то же самое, что делает Gnibbler, но я должен был написать это первым, прежде чем я смогу полностью понять свою функцию лямбда.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top