Python3:创建字典的选择性副本作为新字典

1 投票
1 回答
1306 浏览
提问于 2025-04-17 15:36

我使用的是Python 3.3.0,从一个csv文件中创建了一个“字典”(文件的表头是:ID;Col1;Col2;Col3;Col4;Col5):

ID;Col1;Col2;Col3;Col4;Col5
15345;1;1;nnngngn;vhrhtnz;latest
12345;12;8;gnrghrtthr;tznhltrnhklr;latest
90834;3;4;something;nonsens;latest
12345;34;235;dontcare;muhaha;oldone

用的代码是

file = "test.csv" 
csv_file = csv.DictReader(open(file, 'r'), delimiter=';', quotechar='"')

我想把ID为12345的行复制到一个新的字典里,而不是复制到文件中。我真的需要复制到字典里,而不是列表,因为我想直接用列名来访问数据。

我尝试这样做

cewl = {}
for row in csv_file:
   if row['ID'] == '12345':
   cewl.update(row)
print(cewl)

输出结果是:

{'ID': '12345', 'Col1': '34', 'Col2': '235', 'Col3': 'dontcare', 'Col4': 'muhaha', 'Col5': 'oldone'}

我的问题:只有第二行ID为12345的数据被复制了,第一行却没有,我不知道为什么。

如果我尝试把数据复制到一个新的列表(只是为了测试),一切都正常:

cewl = []
for row in csv_file1:
if row['ID'] == '12345':
    cewl.append(row)
print(cewl)

输出结果是:

[{'Col3': 'gnrghrtthr', 'Col2': '8', 'Col1': '12', 'Col5': 'latest', 'Col4': 'tznhltrnhklr', 'ID': '12345'}, 
{'Col3': 'dontcare', 'Col2': '235', 'Col1': '34', 'Col5': 'oldone', 'Col4': 'muhaha', 'ID': '12345'}]

我不知道为什么在复制到新的字典时会出现这个问题……看起来dictreader没有像.add或.append那样的方法。

我该如何把我的数据复制到新的字典中而不漏掉任何行呢?

1 个回答

2

你期待的输出是什么呢?这个行为对于一个 dict 来说是完全正常的;你实际上是在用一个新值来 替换 每个键对应的值。

如果你想让每个匹配的行的值变成 列表,那么使用一个带有 list 工厂的 defaultdict 会更简单:

from collections import defaultdict

cewl = defaultdict(list)

for row in csv_file:
   if row['ID'] == '12345':
       for k, v in row.items():
           cewl[k].append(v)

print(cewl)

这样输出的结果是:

defaultdict(<class 'list'>, {'Col1': ['12', '34'], 'ID': ['12345', '12345'], 'Col2': ['8', '235'], 'Col5': ['latest', 'oldone'], 'Col4': ['tznhltrnhklr', 'muhaha'], 'Col3': ['gnrghrtthr', 'dontcare']})

defaultdictdict 的一个子类,所以 print(cewl['Col1']) 会输出 ['12', '34']

当你使用 .update() 方法时,实际上是做了这样的事情:

for k, v in row.items():
    cewl[k] = v

比如说,把 cewl 中的每个键设置为正在处理的行中的值。当最后一行被处理时,它的值会覆盖之前行的值。

如果你想筛选出只符合某个 ID 条件的行,把它们添加到一个列表中是完全可以的。然后你可以遍历这些匹配的结果来处理它们:

for row in cewl:
    # do something with matched row

或者你可以构建一个生成器过滤器,把它包裹在你的 DictReader() 周围,这样可以帮你进行过滤,这样你就不需要在内存中构建列表了:

def rowfilter(reader, id):
    for row in reader:
        if row['ID'] == id:
            yield row

for row in rowfilter(csv_file, '12345'):
    # do something with matched row

撰写回答