Удаление элемента из списка внутри dict в Python - PullRequest
4 голосов
/ 04 июня 2019
{  
   'tbl':'test',
   'col':[  
      {  
         'id':1,
         'name':"a"
      },
      {  
         'id':2,
         'name':"b"
      },
      {  
         'id':3,
         'name':"c"
      }
   ]
}

У меня есть словарь, подобный приведенному выше, и я хочу удалить элемент с id=2 из списка внутри него. Я потратил полдня на размышления, почему modify2 не работает с операцией del. Пробовал pop и похоже, что работает, но я не совсем понимаю, почему del не работает.

Есть ли способ удаления с помощью del или pop - идеальный способ решения этого варианта использования?

import copy

test_dict = {'tbl': 'test', 'col':[{'id':1, 'name': "a"}, {'id':2, 'name': "b"}, {'id':3, 'name': "c"}]}

def modify1(dict):
    new_dict = copy.deepcopy(dict)
    # new_dict = dict.copy()
    for i in range(len(dict['col'])):
        if dict['col'][i]['id'] == 2:
            new_dict['col'].pop(i)
    return new_dict

def modify2(dict):
    new_dict = copy.deepcopy(dict)
    # new_dict = dict.copy()
    for i in new_dict['col']:
        if i['id']==2:
            del i
    return new_dict

print("Output 1 : " + str(modify1(test_dict)))
print("Output 2 : " + str(modify2(test_dict)))

Выход:

Output 1 : {'tbl': 'test', 'col': [{'id': 1, 'name': 'a'}, {'id': 3, 'name': 'c'}]}
Output 2 : {'tbl': 'test', 'col': [{'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'}, {'id': 3, 'name': 'c'}]}

Я пытался найти ответы на похожие вопросы, но не нашел того, который устранял бы мою путаницу.

Ответы [ 5 ]

3 голосов
/ 04 июня 2019

В Python 3 вы можете сделать это:

test_dict = {**test_dict, 'col': [x for x in test_dict['col'] if x['id'] != 2]}
2 голосов
/ 04 июня 2019

del i просто говорит интерпретатору, что i (произвольная локальная переменная / имя, которое происходит со ссылкой на словарь) больше не должно ссылаться на этот словарь.Он не изменяет содержание этого словаря.

Это можно визуализировать на http://www.pythontutor.com/visualize.html:

До del i.Примечание i ссылается на второй словарь (отмечен синей линией):

enter image description here

После del i.Обратите внимание, как локальная переменная i удаляется из локального пространства имен (синее поле), но словарь, на который она ссылается, все еще существует.

enter image description here

Наоборотна del i (который изменяет ссылку на словарь), dict.pop(key) изменяет словарь .

1 голос
/ 04 июня 2019

Вы не можете удалить элемент, на который ссылается итерационная переменная (i) в цикле for

l = [1,2,3]
for i in l:
    if i == 2:
        del i

не будет работать. l все равно будет [1,2,3]

что вы можете сделать, это получить индекс этого элемента и удалить его с помощью индекса

l = [1,2,3]
for idx, elem in enumerate(l):
    if elem == 2:
        del l[idx]
1 голос
/ 04 июня 2019

Причина, по которой он не работает, заключается в том, что вы используете del неправильно.

Если у вас есть словарь d = {'a': [{'id':1}, {'id':2}]} Затем, чтобы удалить второй элемент словаря, который вы используете del d['a'][1], это возвращает d = {'a': [{'id':1}]}

Итак, для вашей проблемы вы итерируете, чтобы найти позицию id 2 в списке, а затем можете просто сделать del dict['col'][ix], где ix - индекс id 2 в списке

1 голос
/ 04 июня 2019

Это один подход, использующий понимание.

Ex:

data = {'tbl': 'test', 'col': [{'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'}, {'id': 3, 'name': 'c'}]}

data['col'] = [i for i in data['col'] if i["id"] != 2]
print(data)

Выход:

{'col': [{'id': 1, 'name': 'a'}, {'id': 3, 'name': 'c'}], 'tbl': 'test'}
...