2013-02-25 5 views
2

У меня есть список словарей в Python. Каждый элемент списка имеет ключ type с типом элемента. Что-то вроде этого:Pythonic способ сравнения нескольких элементов в списке словарей

e1 = {"type": 1, "value": 23.1} 
e2 = {"type": 1, "value": 21.1} 
e3 = {"type": 2, "value": -10.1} 
e4 = {"type": 1, "value": -2.59} 
l = [e1, e2, e3, e4] 

Я хотел бы знать, если все элементы в списке l одного и того же type.

У меня есть это:

def same_type(l): 
    return l[0].type == l[1].type == l[2].type == l[3].type 

список Предполагая, что всегда будет иметь тот же размер, есть более вещий способ сделать это?

+1

не только все ответы, но я тоже вам вопрос ... –

ответ

8

Первое, что приходит в голову:

all(e['type'] == L[0]['type'] for e in L) 

Длина набора типов:

len(set(e['type'] for e in L)) == 1 

является более эффективным, чем all с генератором, но не со списком:

>>> %timeit all(e['type'] == l[0]['type'] for e in l) 
1000000 loops, best of 3: 784 ns per loop 

>>> %timeit len(set(e['type'] for e in l)) == 1 
1000000 loops, best of 3: 676 ns per loop 

>>> %timeit all([e['type'] == l[0]['type'] for e in l]) 
1000000 loops, best of 3: 602 ns per loop 

С кэшированным l[0]['type']:

>>> t1 = l[0]['type'] 
>>> %timeit all([e['type'] == t1 for e in l]) 
1000000 loops, best of 3: 447 ns per loop 

>>> %timeit all(e['type'] == t1 for e in l) 
1000000 loops, best of 3: 655 ns per loop 

set со списком-комп даже медленнее, чем с genexpr:

>>> %timeit len(set([gettype(e) for e in l])) == 1 
1000000 loops, best of 3: 735 ns per loop 

 

я думал о другом способе, которым это быстрее, чем set, когда нет возможности короткого замыкания :

>>> %timeit [e['type'] for e in l].count(t1) == len(l) 
1000000 loops, best of 3: 421 ns per loop 

 

Другой редактирование: по-видимому, самый простой метод является самым быстрым:

In [31]: def same_type(L): 
    ....:  t1 = L[0]['type'] 
    ....:  for e in L: 
    ....:   if e['type'] != t1: 
    ....:    return False 
    ....:  return True 
    ....: 

In [32]: %timeit same_type(l) 
1000000 loops, best of 3: 352 ns per loop 

Длинный вход с того же типа (нет короткого замыкания)

In [47]: l = [{'type': 1} for _ in range(1000)] 

In [48]: %timeit same_type(l) 
10000 loops, best of 3: 37.6 us per loop 

In [49]: %timeit all(e['type'] == l[0]['type'] for e in l) 
10000 loops, best of 3: 112 us per loop 

In [50]: %timeit all([e['type'] == l[0]['type'] for e in l]) 
10000 loops, best of 3: 103 us per loop 

In [51]: %timeit len(set(e['type'] for e in l)) == 1 
10000 loops, best of 3: 63.3 us per loop 

Длинный вход с различными типами (короткое замыкание сразу)

In [40]: l = [{'type': x} for x in range(1000)] 

In [43]: %timeit same_type(l) 
1000000 loops, best of 3: 337 ns per loop 

In [44]: %timeit all(e['type'] == l[0]['type'] for e in l) 
1000000 loops, best of 3: 656 ns per loop 

In [45]: %timeit all([e['type'] == l[0]['type'] for e in l]) 
10000 loops, best of 3: 99.4 us per loop 

In [46]: %timeit len(set(e['type'] for e in l)) == 1 
10000 loops, best of 3: 68.6 us per loop 
+0

Я думаю, что это должно быть 'L [0] ['type']'? –

+2

Будьте очень осторожны с настройками времени. 'all' с генератором будет выбивать список, если вы получите ввод, который хорош для короткого замыкания. Кроме того, вы не пробовали 'set' со списком-comp, который может (или не может) лучше, чем' set' с genexp. – mgilson

+0

Видимо, ручная кодировка 'all' является самой эффективной. –

4

Работы для любой длины lst:

def same_type(lst): 
    return all(d['type'] == lst[0]['type'] for d in lst[1:]) 

сравнивающих к len(set(...)) == 1 это быстрее, потому что он останавливается, как только другой type найден.

5

Используйте set() собрать все типы, а затем проверить, если это длина 1:

def same_type(L): 
    if not L: return True # empty list case 
    return len(set(d['type'] for d in L)) == 1 

Это будет сканировать все элементы. Кроме того, можно сравнить против первого элемента, после чего вам нужно только проверить достаточно, чтобы найти тот, который не соответствует:

def same_type(L): 
    if not L: return True # empty list case 
    t = L[0]['type'] 
    return all(t == d['type'] for d in L) 

Для меньше вводит set() подход быстрее, но для более крупный входы второй формы могут выбить set(), если вероятность наличия второго входа во входе достаточно велика.

+0

wow ... симпатичный умный. было бы быстрее, чем два других ответа (которые в основном одинаковы ...) –

+1

@PabloSantaCruz: Я ожидаю, что 'all()' будет быстрее. –

+0

Если 'd' велико, и производительность действительно имеет значение, вам нужно кэшировать' l [0] ['type'] '. –

Смежные вопросы