【问题标题】:Python3: create selective copy of dictionary as a new dictionaryPython3:创建字典的选择性副本作为新字典
【发布时间】:2013-01-27 15:00:46
【问题描述】:

使用 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'}]

我不知道为什么通过复制到新字典中这不起作用...似乎没有像 .add 或 .append 这样的方法用于 dictreader。

如何将我的数据复制到新字典中而不丢失任何行?

【问题讨论】:

  • 字典是一个映射;决定是否要将 ID ('12345') 映射到示例中的两个或多个不同的数据,在这种情况下,您可以将 ID 映射到包含键 Col1、@ 的不同值映射的字典列表987654329@ 等或类似元组列表(ID, Col1, Col2, etc)。在编写任何代码之前考虑您的数据结构。

标签: python dictionary python-3.x copy


【解决方案1】:

预期的输出是什么? dict 的行为是完全正常的;您正在用新值替换每个键的值。

如果您希望值是每个匹配行的值的列表,则使用defaultdictlist 工厂会更容易:

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

【讨论】:

  • @dacoda:python 映射对象将键映射到 one 值。所以somedict['a'] = 1 后跟someddict['a'] = 2 意味着您替换了'a' 的值。我提出的解决方案为您提供了一个列表值,我们会在找到项目时将它们添加到该列表中。不过,我不确定您是否了解 python 映射的工作原理。
  • 如果您需要一个字典列表,请使用您的列表并将行追加到该列表中。
  • @dacoda:我能够很好地阅读您的评论,请不要在有评论时编辑答案。我希望你给我 exact 预期的输出,而不是你已经发布的(因为“类似但不同的东西”不清楚)。
  • :谢谢,我想创建一个我的字典的副本,其中只包含 ID=12345 的行,因此在这种情况下 cewl 的预期输出应该是标题和两行,每行 ID 为 12345对应的数据。
  • @dacoda:你想做什么?写出过滤的csv 文件? DictReader 为您提供dict 对象的序列,就像您的列表输出一样,每个对象的每一行都有相同的键。你需要更清楚你想要做什么,我仍然只是在这里猜测。
猜你喜欢
  • 1970-01-01
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 2012-09-20
  • 1970-01-01
相关资源
最近更新 更多