Подсчет записей в списке словарей: цикл и понимание списка с картой (itemgetter) - PullRequest
4 голосов
/ 07 июня 2010

В программе на Python, которую я пишу, я сравнивал использование переменных цикла и приращения for и понимания списка со значениями map(itemgetter) и len() при подсчете записей в словарях, находящихся в списке.Это занимает то же время, используя каждый метод.Я делаю что-то не так или есть лучший подход?

Вот очень упрощенная и сокращенная структура данных:

list = [
  {'key1': True, 'dontcare': False, 'ignoreme': False, 'key2': True, 'filenotfound': 'biscuits and gravy'},
  {'key1': False, 'dontcare': False, 'ignoreme': False, 'key2': True, 'filenotfound': 'peaches and cream'},
  {'key1': True, 'dontcare': False, 'ignoreme': False, 'key2': False, 'filenotfound': 'Abbott and Costello'},
  {'key1': False, 'dontcare': False, 'ignoreme': True, 'key2': False, 'filenotfound': 'over and under'},
  {'key1': True, 'dontcare': True, 'ignoreme': False, 'key2': True, 'filenotfound': 'Scotch and... well... neat, thanks'}
]

Вот версия цикла for:

#!/usr/bin/env python
# Python 2.6
# count the entries where key1 is True
# keep a separate count for the subset that also have key2 True

key1 = key2 = 0
for dictionary in list:
    if dictionary["key1"]:
        key1 += 1
        if dictionary["key2"]:
            key2 += 1
print "Counts: key1: " + str(key1) + ", subset key2: " + str(key2)

Вывод для данных выше:

Counts: key1: 3, subset key2: 2

Вот другая, возможно, более Pythonic, версия:

#!/usr/bin/env python
# Python 2.6
# count the entries where key1 is True
# keep a separate count for the subset that also have key2 True
from operator import itemgetter
KEY1 = 0
KEY2 = 1
getentries = itemgetter("key1", "key2")
entries = map(getentries, list)
key1 = len([x for x in entries if x[KEY1]])
key2 = len([x for x in entries if x[KEY1] and x[KEY2]])
print "Counts: key1: " + str(key1) + ", subset key2: " + str(key2)

Вывод для данных выше (аналогично предыдущему):

Counts: key1: 3, subset key2: 2

Я немного удивлен, что это занимает столько же времени.Интересно, есть ли что-нибудь быстрее?Я уверен, что пропускаю что-то простое.

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

Я не могу контролировать исходную форму данных.

Приведенный выше код не подходит для стилей.

1 Ответ

12 голосов
/ 07 июня 2010

Я думаю, что вы измеряете неправильно, затягивая код, который нужно измерить, с большими накладными расходами (работа на верхнем уровне модуля вместо функции, выполнение вывода).Помещение двух фрагментов в функции с именами forloop и withmap и добавление * 100 к определению списка (после закрытия ]), чтобы сделать измерение немного более существенным, как я вижу, на моем медленном ноутбуке:

$ py26 -mtimeit -s'import co' 'co.forloop()'
10000 loops, best of 3: 202 usec per loop
$ py26 -mtimeit -s'import co' 'co.withmap()'
10 loops, best of 3: 601 usec per loop

то есть, якобы «более питонический» подход с map в три раза медленнее, чем простой for подход, который говорит вам, что он на самом деле не «более питонический»; -).

Знак хорошего Python - это простота , что, по-моему, рекомендует то, что я с гордостью назвал ...:

def thebest():
  entries = [d['key2'] for d in list if d['key1']]
  return len(entries), sum(entries)

, которое при измерении экономитот 10% до 20% времени в подходе forloop.

...