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