Python: удалить словарь из списка

Если у меня есть список словарей, скажите:

[{'id': 1, 'name': 'paul'}, {'id': 2, 'name': 'john'}] 

и я хотел бы удалить словарь с id 2 (или именем john), что является наиболее эффективным способом сделать это программно (то есть, я не знаю индекс записи в списке, чтобы он нельзя просто выскочить).

7 Solutions collect form web for “Python: удалить словарь из списка”

 thelist[:] = [d for d in thelist if d.get('id') != 2] 

Редактирование : поскольку некоторые сомнения были высказаны в комментарии о производительности этого кода (некоторые из них основаны на непонимании характеристик производительности Python, некоторые из которых полагают, что за пределами указанных спецификаций в списке есть ровно один dict, со значением 2 для ключа ' id '), я хочу предложить заверения в этом вопросе.

На старом Linux-поле, измеряющем этот код:

 $ python -mtimeit -s"lod=[{'id':i, 'name':'nam%s'%i} for i in range(99)]; import random" "thelist=list(lod); random.shuffle(thelist); thelist[:] = [d for d in thelist if d.get('id') != 2]" 10000 loops, best of 3: 82.3 usec per loop 

из которых около 57 микросекунд для random.shuffle (необходимо для того, чтобы удалить элемент не ВСЕГДА на том же месте 😉 и 0,65 мкс для начальной копии (кто бы ни беспокоился о влиянии производительности мелких копий списков Python очевидно, чтобы обедать ;-), чтобы избежать изменения исходного списка в цикле (так что каждая нога цикла имеет что-то удалить ;-).

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

 $ python -mtimeit -s"lod=[{'id':i, 'name':'nam%s'%i} for i in range(99)]; import random" "thelist=list(lod); random.shuffle(thelist); where=(i for i,d in enumerate(thelist) if d.get('id')==2).next(); del thelist[where]" 10000 loops, best of 3: 72.8 usec per loop 

(используйте next встроенный, а не метод .next если вы на Python 2.6 или лучше, конечно), но этот код разрушается, если число dicts, удовлетворяющих условию удаления, не является одним. Обобщая это, мы имеем:

 $ python -mtimeit -s"lod=[{'id':i, 'name':'nam%s'%i} for i in range(33)]*3; import random" "thelist=list(lod); where=[i for i,d in enumerate(thelist) if d.get('id')==2]; where.reverse()" "for i in where: del thelist[i]" 10000 loops, best of 3: 23.7 usec per loop 

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

 $ python -mtimeit -s"lod=[{'id':i, 'name':'nam%s'%i} for i in range(33)]*3; import random" "thelist=list(lod); thelist[:] = [d for d in thelist if d.get('id') != 2]" 10000 loops, best of 3: 23.8 usec per loop 

полностью шею и шею, и даже удалить 3 элемента из 99. С более длинными списками и большим количеством повторений это, конечно, еще больше:

 $ python -mtimeit -s"lod=[{'id':i, 'name':'nam%s'%i} for i in range(33)]*133; import random" "thelist=list(lod); where=[i for i,d in enumerate(thelist) if d.get('id')==2]; where.reverse()" "for i in where: del thelist[i]" 1000 loops, best of 3: 1.11 msec per loop $ python -mtimeit -s"lod=[{'id':i, 'name':'nam%s'%i} for i in range(33)]*133; import random" "thelist=list(lod); thelist[:] = [d for d in thelist if d.get('id') != 2]" 1000 loops, best of 3: 998 usec per loop 

В целом, очевидно, не стоит развертывать тонкость создания и изменения списка индексов для удаления, а также совершенно простого и очевидного понимания списка, чтобы, возможно, получить 100 наносекунд в одном маленьком случае – и потерять 113 микросекунд в более крупном ;-). Избежать или критиковать простые, простые и идеально подходящие для исполнения решения (например, понимание списков для этого общего класса «удалить некоторые предметы из списка») – особенно неприятный пример известного тезиса Кнута и Хора, что «преждевременная оптимизация корень всего зла в программировании "! -)

Это не совсем anwser (как я думаю, у вас уже есть некоторые неплохие из них), но … вы считаете, что у вас есть словарь <id>:<name> вместо списка словарей?

Вот способ сделать это с пониманием списка (если вы назовете свой список «foo»):

 [x for x in foo if not (2 == x.get('id'))] 

Замените 'john' == x.get('name') или что угодно, если необходимо.

filter также работает:

foo.filter(lambda x: x.get('id')!=2, foo)

И если вы хотите генератор, вы можете использовать itertools:

itertools.ifilter(lambda x: x.get('id')!=2, foo)

Однако, как и в случае с Python 3, filter все равно вернет итератор, поэтому понимание списка действительно лучший выбор, как предложил Алекс.

list.pop () – хороший выбор:

 >>> a = [{'id': 1, 'name': 'paul'}, ... {'id': 2, 'name': 'john'}] >>> a.pop(1) {'id': 2, 'name': 'john'} >>> a [{'id': 1, 'name': 'paul'}] 

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

 >>> a = [{'id': 1, 'name': 'paul'}, ... {'id': 2, 'name': 'john'}] >>> for i in reversed(range(len(a))): ... if a[i].get('id') == 2: ... a.pop(i) ... {'id': 2, 'name': 'john'} >>> a [{'id': 1, 'name': 'paul'}] 

Другая возможность – использовать del:

 [{'id': 1, 'name': 'paul'}] >>> a = [{'id': 1, 'name': 'paul'}, ... {'id': 2, 'name': 'john'}] >>> a [{'id': 1, 'name': 'paul'}, {'id': 2, 'name': 'john'}] >>> del a[1] >>> a [{'id': 1, 'name': 'paul'}] 
 # assume ls contains your list for i in range(len(ls)): if ls[i]['id'] == 2: del ls[i] break 

Вероятно, будет быстрее, чем методы понимания списка в среднем, потому что он не пересекает весь список, если он находит этот предмет на ранней стадии.

Вы можете попробовать что-то в следующих строках:

 def destructively_remove_if(predicate, list): for k in xrange(len(list)): if predicate(list[k]): del list[k] break return list list = [ { 'id': 1, 'name': 'John' }, { 'id': 2, 'name': 'Karl' }, { 'id': 3, 'name': 'Desdemona' } ] print "Before:", list destructively_remove_if(lambda p: p["id"] == 2, list) print "After:", list 

Если вы не создадите что-то похожее на индекс над вашими данными, я не думаю, что вы можете сделать лучше, чем выполнять «сканирование таблицы грубой силы» по всему списку. Если ваши данные отсортированы с помощью ключа, который вы используете, вы можете использовать модуль bisect, чтобы найти объект, который вы ищете, несколько быстрее.

Вы можете попробовать следующее:

 a = [{'id': 1, 'name': 'paul'}, {'id': 2, 'name': 'john'}] for e in range(len(a) - 1, -1, -1): if a[e]['id'] == 2: a.pop(e) 

Если вы не можете поп с самого начала – поп с конца, это не испортит цикл for.

  • Pythonic способ распечатать элементы списка
  • одиночный список в словарь
  • Pythonic способ конвертировать список dicts в список namedtuples
  • OOP python - удаление экземпляра класса из списка
  • суммировать список чисел в Python
  • удалить значение None из списка без удаления значения 0
  • Итерация на языке Python списка объектов «не повторяется»
  • Преобразование чисел в классы в списке python
  • Вставить в первую позицию списка в Python
  • Списки сумм различной длины
  • Может ли список, набор или словарь Python быть реализован невидимо с помощью базы данных?
  • Python - лучший язык программирования в мире.