2009-11-19 3 views
19

не уверен, что это задавали раньше, но я не мог найти очевидного ответа. Я пытаюсь подсчитать количество элементов в списке, равное определенному значению. Проблема в том, что эти элементы не имеют встроенного типа. Так что, если у меня естьУсловный подсчет в Python

class A: 
    def __init__(self, a, b): 
     self.a = a 
     self.b = b 

stuff = [] 
for i in range(1,10): 
    stuff.append(A(i/2, i%2)) 

Теперь я хотел бы подсчет элементов списка, поле которых Ь = 1. Я пришел с двумя решениями:

print [e.b for e in stuff].count(1) 

и

print len([e for e in stuff if e.b == 1]) 

Какие лучший метод? Есть ли лучшая альтернатива? Кажется, что метод подсчета() не принимает ключи (по крайней мере, в Python версии 2.5.1.

Большое спасибо!

+1

Это не является хорошей идеей назвать список как «список». – MAK

+0

Я полностью согласен и изменил название списка. – nicolaum

ответ

35
sum(x.b == 1 for x in L) 

Логическое (как результат сравнения, таких как x.b == 1) также int, со значением 0 для False, 1 для True, поэтому арифметика, такая как суммация работает просто отлично.

Это простейший код, но, возможно, не самый быстрый (только timeit может вам точно сказать ;-). Рассмотрим (упрощенный случай, хорошо помещается на командных строк, но эквивалент):

$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'len([x for x in L if x==1])' 
10000 loops, best of 3: 56.6 usec per loop 
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'sum(x==1 for x in L)' 
10000 loops, best of 3: 87.7 usec per loop 

Таким образом, в этом случае, «память расточительно» подход генерирования дополнительного временного списка и проверки его длины на самом деле солидно быстрее проще, короче, экономнее, я предпочитаю. Разумеется, другие сочетания значений списка, реализации Python, доступности памяти для «инвестирования» в это ускорение и т. Д. Могут повлиять на точную производительность.

+1

Не стоит объяснять, как это работает. Для всех не будет очевидно, что вы можете добавить список логических элементов. –

+1

Кроме того, почему это лучший подход, чем: len ([e для e в списке, если e.b == 1]) , которому не нужно суммировать элементы? – nicolaum

+0

Без учета позиции, которая лучше всего подходит, это позволяет избежать формирования целого списка, который фактически не нужен ни для чего. –

10
print sum(1 for e in L if e.b == 1) 
+3

Приятный, я думаю, что это более читаемая версия ответа Алекса Мартелли, суммирование 1 более очевидно, чем знание того, что True можно рассматривать как 1. –

+1

Он также хорошо зарекомендовал себя как общий шаблон: 'sum (len (n) for n в L, если nb == 1) 'например. – 2009-11-19 17:36:28

+0

@TendayiMawushe: суммирование '1' вместо булевых значений также примерно на 30% быстрее, по крайней мере, с использованием Python 2.7 (см. Мой комментарий к ответу Alex). –

2

Я бы предпочел второй, как это только цикл по списку раз .

Если вы используете count() вы зацикливание на список один раз, чтобы получить b значения, а затем цикл над ним снова, чтобы увидеть, сколько из них равны 1.

аккуратный способ может использовать reduce():

reduce(lambda x,y: x + (1 if y.b == 1 else 0),list,0) 

The documentation говорит нам, что reduce() будет:

Применить функцию двух аргументов кумулятивны пунктам итерации, слева направо, таким образом, чтобы уменьшить итерацию до одного значения.

Таким образом, мы определим lambda, который добавляет один накопленное значение, только если атрибут элемента списка b является 1.

+0

Мне нравится этот подход лучший. Не понимаю, почему он не получает никаких выплат. – phunehehe

+0

@phunehehe: Я полагаю, что он не получил upvotes, так как это, безусловно, самая медленная * и * самая многословная альтернатива, предложенная здесь. –

+0

Забавный, я больше не помню. Возможно, этот ответ соответствует тому, что я делаю (чего я тоже не помню): D – phunehehe

0

Чтобы скрыть reduce детали, вы можете определить count функцию:

def count(condition, stuff): 
    return reduce(lambda s, x: \ 
        s + (1 if condition(x) else 0), stuff, 0) 

Затем вы можете использовать его, обеспечивая условия для подсчета:

n = count(lambda i: i.b, stuff) 
Смежные вопросы