Наиболее питонический способ подсчета совпадающих элементов в чем-то итерируемом - PullRequest
14 голосов
/ 01 октября 2008

У меня есть итерация записей, по которым я хотел бы собрать некоторую простую статистику, скажем, счет всех чисел, делимых на два, и счет всех чисел, делимых на три.

Моя первая альтернатива, хотя и повторяющаяся по списку только один раз и избегающая расширения списка (и помня о рефакторинге split *1004*), выглядит довольно раздутой:

(альт 1)

r = xrange(1, 10)

twos = 0
threes = 0

for v in r:
  if v % 2 == 0:
    twos+=1
  if v % 3 == 0:
    threes+=1

print twos
print threes

Это выглядит довольно красиво, но имеет недостаток, заключающийся в расширении выражения до списка:

(альт 2)

r = xrange(1, 10)

print len([1 for v in r if v % 2 == 0])
print len([1 for v in r if v % 3 == 0])

Что мне действительно нужно, так это что-то вроде этой функции:

(альт 3)

def count(iterable):
  n = 0
  for i in iterable:
    n += 1
  return n

r = xrange(1, 10)

print count(1 for v in r if v % 2 == 0)
print count(1 for v in r if v % 3 == 0)

Но это очень похоже на то, что можно сделать без функции. Окончательный вариант таков:

(alt 4)

r = xrange(1, 10)

print sum(1 for v in r if v % 2 == 0)
print sum(1 for v in r if v % 3 == 0)

и хотя самый маленький (и в моей книге, вероятно, самый элегантный), он не очень хорошо выражает намерение.

Итак, мой вопрос к вам:

Какая альтернатива вам больше нравится для сбора этих типов статистики? Не стесняйтесь предлагать собственную альтернативу, если у вас есть что-то лучше.

Чтобы устранить некоторую путаницу ниже:

  • На самом деле мои предикаты фильтра более сложны, чем просто этот простой тест.
  • Объекты, которые я перебираю, больше и сложнее, чем просто числа
  • Мои функции фильтра более различны и их трудно параметризировать в один предикат

Ответы [ 12 ]

0 голосов
/ 01 октября 2008

Не так кратко, как вы ищете, но более эффективно, на самом деле он работает с любыми повторяемыми, а не только повторяемыми циклами, которые вы можете циклически повторять несколько раз, и вы можете расширять проверяемые объекты, не усложняя их далее:

r = xrange(1, 10)

counts = {
   2: 0,
   3: 0,
}

for v in r:
    for q in counts:
        if not v % q:
            counts[q] += 1
        # Or, more obscure:
        #counts[q] += not v % q

for q in counts:
    print "%s's: %s" % (q, counts[q])
0 голосов
/ 01 октября 2008

Я бы определенно посмотрел на массив numpy вместо итеративного списка, если у вас есть только числа. Вы почти наверняка сможете делать что угодно с некоторой краткой арифметикой в ​​массиве.

...