【问题标题】:Converting CSV data to list in dictionary将 CSV 数据转换为字典中的列表
【发布时间】:2015-06-24 05:06:27
【问题描述】:

我有一个格式如下的 CSV 文件:

Name_1,2,K,14
Name_1,3,T,14
Name_1,4,T,18
Name_2,2,G,12
Name_2,4,T,14
Name_2,6,K,15
Name_3,2,K,12
Name_3,3,T,15
Name_3,4,G,18

我想将它转换成一个字典,其中Name_x 是键,对应的数据是列表形式的值。像这样的:

{'Name_1': [[2, 'K', 14], [3, 'T', 14], [4, 'T', 18]],
 'Name_2': [[4, 'T', 14], [4, 'T', 14], [6, 'K' ,15]],
...}

到目前为止,我想我必须使用defaultdict

from collections import defaultdict
d = defaultdict(list)

但是我如何将append 的数据发送到d?我知道defaultdict 没有append 方法。

【问题讨论】:

  • d[key].append(new_val)?

标签: python csv python-3.x dictionary defaultdict


【解决方案1】:

您需要使用名称作为键并附加行的切片作为值,使用普通或默认字典将没有顺序:

import csv
from collections import defaultdict

with open('in.csv') as f:
    r = csv.reader(f)
    d = defaultdict(list)
    for row in r:
        d[row[0]].append(row[1:])
print(d)

如果您想维持秩序,您需要OrderedDict

from collections import OrderedDict

with open('in.csv') as f:
    r = csv.reader(f)
    od = OrderedDict()
    for row in r:
        # get key/ first element in row
        key = row[0]
        # create key/list paring if it does not exist, else just append the value
        od.setdefault(key, []).append(row[1:])
print(od)

输出:

OrderedDict([('Name_1', [['2', 'K', '14'], ['3', 'T', '14'], ['4', 'T', '18']]), ('Name_2', [['2', 'G', '12'], ['4', 'T', '14'], ['6', 'K', '15']]), ('Name_3', [['2', 'K', '12'], ['3', 'T', '15'], ['4', 'G', '18']])])

如果名称被分组,您也可以使用 groupby,这将根据每行中的第一个项目/名称对元素进行分组:

import csv
from collections import OrderedDict
from itertools import groupby
from operator import itemgetter

with open('in.csv') as f:
    r = csv.reader(f)
    od = OrderedDict()
    for k, v in groupby(r, key=itemgetter(0)):
        od[k] = [sub[1:] for sub in v]

如果你使用python3,你可以使用*解包:

with open("in.csv") as f:
    r = csv.reader(f)
    od = OrderedDict()
    for row in r:
        key, *rest = row
        od.setdefault(key, []).append(rest)


import csv
from collections import OrderedDict
from itertools import groupby
from operator import itemgetter

with open('in.csv') as f:
    r = csv.reader(f)
    od = OrderedDict()
    for k, v in groupby(r, key=itemgetter(0)):
        od[k] = [sub for _, *sub in v]
print(od)

【讨论】:

  • 小改进:key = row.pop(0) 然后 od.setdefault(key, []).append(row)
  • 这行得通,谢谢!很高兴你也添加了 OrderedDict 可能性——这正是我想要的。实际上是否可以通过索引访问值?所以例如Name_1[1] 会给我'K','T','T'。我可以通过["Name_1"][1][1] 访问单个字母,但我需要所有字母(以相同的顺序)。
  • @Hjalte,当然只是print(list(zip(*od["Name_1"]))[1]),它将转置子列表或print([sub[1] for sub in od["Name_1"]])
  • @simleo,你能解释一下,为什么这是一个改进? (我是 Python 新手)。
  • @Hjalte 因为 row[1:] 复制了几乎整个列表。既然你要把它扔掉,你可以只弹出第一个元素,这样剩下的就是你需要构建字典的子列表
【解决方案2】:
txtcsv="""Name_1,2,K,14
Name_1,3,T,14
Name_1,4,T,18
Name_2,2,G,12
Name_2,4,T,14
Name_2,6,K,15
Name_3,2,K,12
Name_3,3,T,15
Name_3,4,G,18"""

def save():
    with open("test.csv","w") as f:
        f.write(txtcsv)


if __name__ == "__main__":
    save()
    with open("test.csv") as f:
        d = {}
        for l in f.readlines():
            name, val = l.rstrip().split(",", 1)
            d.setdefault(name, []).append(val.split(","))
        print (d)

【讨论】:

  • 不是我的反对意见,但无需将所有行读入内存,自动关闭文件,因此 f.close() 是多余的。您还可以使用 rstrip 从字符串末尾删除并使用 dict.setdefault 处理重复键..
  • @PadraicCunningham 当然是关闭!没错,剥两边是没用的!我不习惯使用 setdefault 但它确实更好。谢谢!
  • 我对它投了反对票,因为您不使用 csv 库。这显然是您应该使用它的情况。我敢打赌,有很多事情可能会出错,但在我的头上;如果名称包含逗号怎么办?请记住,Python 包含电池。
  • @SteinarLima 请注意,从未提及代码必须与任何 CSV 一起使用,即使标题可以建议它,问题也涉及具有提供格式的特定文件。所以这段代码回答了发布的问题。下次 SteinarLima 请不要在没有解释的情况下投反对票(没用),并考虑对所提问题的回应。
  • 呃,你不知道Name_1是什么,万一明天改了呢?在 Python 中包含 csv 库时不使用它是愚蠢的。最重要的是,您不使用defaultdict,这显然非常适合这个问题,并且在问题中特别提到。并且如果选择使用,请不要在每次迭代时设置默认值。
【解决方案3】:

在我的脑海中(因为我对 defaultdict 不太熟悉),这应该大致符合您的要求。

数据是 CSV 字符串

obj = {}

data = data.split('\n')
for row in data:
    row = row.split(',')
    if row[0] in obj:
        obj[row[0]].append(row[1:])
    else:
        obj[row[0]] = [row[1:]]

print obj

【讨论】:

  • 好奇为什么是-1?
猜你喜欢
  • 2014-04-24
  • 1970-01-01
  • 2020-01-03
  • 2018-06-23
  • 2021-01-28
  • 1970-01-01
  • 2014-03-01
  • 2019-02-01
  • 2019-04-11
相关资源
最近更新 更多