关于python:迭代时按键从字典中删除元素

Remove element from dictionary by key while iterating

为了从空值中过滤字典列表,我需要从字典中删除大约30%的数据。

所以我得到了这个代码:

1
2
3
4
5
   qr = query_result
   for row in qr:
        for key, value in row.items():
            if value ==' ' or value == None, value == '':
                del row[key]

但是,在执行第一次删除尝试时出错:

RuntimeError: dictionary changed size during iteration

在对stackoverflow进行了一点搜索之后,我找到了解决方案,它包括将所有已删除的值复制到单独的列表中,以便随后删除。

1
2
3
4
5
6
delete = []
for k,v in dict.items():
    if v%2 == 1:
        delete.append(k)
for i in delete:
    del dict[i]

对于我的案例,这种方法可以转换成这样的代码:

1
2
3
4
5
6
7
8
qr = query_result
for row in qr:
    delete = []
    for key, value in row.items():
        if value == ' ' or value == '' or value == None:
            delete.append(key)
    for i in delete:
        del row[i]

同时也受到某些RuntimeError的影响。

因此,删除循环应在dict foreach循环之外:

1
2
3
4
5
6
7
8
qr = query_result
for row in qr:
    delete = []
    for key, value in row.items():
        if value == ' ' or value == '' or value == None:
            delete.append(key)
for i in delete:
    del row[i]

但不幸的是,给定的代码只能正确地修改最后一行。

如何处理所有行,然后删除垃圾数据?

以下是一些测试数据:

1
2
c = [{'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''},
    {'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''}]

我的输出:

1
2
{'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''}
{'A': 'B', 'C': '3', 'P': '343'}

期望输出:

1
2
{'A': 'B', 'C': '3', 'P': '343'}
{'A': 'B', 'C': '3', 'P': '343'}


这里是一个修改您的第一个示例的版本,您需要"复制"您的列表以与它进行迭代并同时删除。在迭代复制的列表之后,可以根据需要从原始列表中删除。

1
2
3
4
5
6
7
8
9
10
11
import copy

qr = [{'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''},
    {'A': 'B', 'C': '3', 'EE': None, 'P': '343', 'AD': ' ', 'B': ''}]

for i, row in enumerate(copy.deepcopy(qr)):
     for key, value in row.items():
         if value in {' ', None, ''}:
             del qr[i][key]

print(qr)

除此之外,通常您希望创建一个新列表,而不是从原始列表中删除。一个简单的列表理解就可以做到这一点:

1
2
3
qr = [{k:v for k, v in row.items() if v not in {' ', None, ''}} for row in qr]

print(qr) # same result

两者的输出:

1
2
[{'A': 'B', 'C': '3', 'P': '343'},
 {'A': 'B', 'C': '3', 'P': '343'}]

您的方法(迭代时收集密钥,然后删除)是正确的。

这是你的问题:

1
2
3
qr = query_result
for row in qr:
    delete = []  # <--- here

每次触摸新行时,都会创建一个新的delete列表。如果有前一行的数据留在其中,则会丢失。

相反,您应该在随后使用它的同一级别(缩进)上创建它:

1
2
3
4
5
6
7
delete = []  # Only once for all rows.
qr = query_result
for row in qr:
   # ...

for k in delete:
  del data[k]


一条直线:

1
c = [{k: v for k, v in d.items() if v not in [' ', '', None]} for d in c]

循环遍历EDOCX1的元素(0),然后对于每个元素只返回匹配的键值对。这将返回:

1
[{'A': 'B', 'P': '343', 'C': '3'}, {'A': 'B', 'P': '343', 'C': '3'}]