【问题标题】:Write dict to csv file with keys not in alphabetic order使用不按字母顺序的键将 dict 写入 csv 文件
【发布时间】:2016-11-14 06:12:45
【问题描述】:

我知道当使用 python 将 dicts 写入 csv 文件时,标题将按字母顺序排列。那么有没有办法可以按照我想要的顺序编写标题?

tsv 文件的代码和输出如下。

我有一个字典:

my_data = {"name": name[:], "city": city[:], "state": state[:],
           "stars": stars[:], "review_count": review_count[:],
           "main_category": new_cat[:]}

我使用以下代码将它们写入 csv 文件:

with open('test.tsv','w') as file:
    writer = csv.writer(file, delimiter='\t')
    writer.writerow(my_data.keys())
    for row in zip(*my_data.values()):
        writer.writerow(list(row))

tsv文件输出的前几行如下:

city    review_count    name    main_category   state   stars
Los Angeles 2   Southern California Medical Group   Medical Centers CA  3.5
Cambridge   4   Harvard Square Shiatsu  Massage MA  4.0
Kitchener   2   Faith & Glory Collective    Tattoo  ON  4.0

您可以看到它们是按字母顺序排列的,但我真正想要的是它们可以按 my_data 中的键顺序排列,如下所示:

name    city    state    stars    review_count    main_category

【问题讨论】:

  • 这个问题的一个或多个答案是否符合您的要求?:stackoverflow.com/questions/1885324/…
  • 但是Dict没有'fieldnames'属性..还有别的办法吗?
  • my_data 中的键没有定义顺序,因为它是字典,而不是序列。
  • @martineau 我意识到了这一点。所以如果我想按这个顺序输出文件,我应该怎么做?
  • @Parker 使用csv.DictWriter 并按照您想要的顺序指定fieldnames...

标签: python csv dictionary


【解决方案1】:

只为一条记录。

import csv

output=open('temp.csv', 'w')
outputCSV = csv.DictWriter(output, delimiter = '\t', \
    fieldnames = [ 'name', 'city', 'state', 'stars', 'review_count', 'main_category' ] )

outputCSV.writerow( {
    'name': 'Southern Cal Med Group',
    'city': 'Los Angeles',
    'state': 'CA',
    'review_count': '2',
    'main_category': 'medical',
    'stars': '3.5',
    } )

output.close()

【讨论】:

  • 我有一个很大的字典。当我这样做时:使用 open('test1.tsv','w') 作为文件: writer = csv.DictWriter(file, delimiter='\t', fieldnames = ["name","city","state ","stars","re​​view_count","main_category"]) for row in zip(*my_data): writer.writerow(list(row)) I got a valueerror "dict contains fields not in fieldnames"
  • 所以使用字段名的问题是,当我继续写 writerow 时,我会得到 valueerror,因为从这个大字典的第二行开始,这些值不是字段名
  • 对我来说听起来像是一个新问题。我有点惊讶作家在收到一份名单时没有抱怨,因为我相信它正在期待一个听写。我会说,只需减少您输入到 writerow 的字典即可。
  • 注意每个 csv 文档 open 应该使用 'wb' 如果 Python 2 和 'w', newline='' 对于 Python 3。这对 Windows 很重要。
【解决方案2】:

以下显示了几种按您想要的顺序将数据输出到 tsv 文件的方法:

with open('test.tsv', 'wb') as file:
    FIELDNAMES = 'name city state stars review_count main_category'.split()
    writer = csv.writer(file, delimiter='\t')
    writer.writerow(FIELDNAMES)
    writer.writerows(row for row in zip(*(my_data[key] for key in FIELDNAMES)))

正如其他人所建议的,这也可以通过使用 csv.DictWriter 来完成:

with open('test.tsv', 'wb') as file:
    FIELDNAMES = 'name city state stars review_count main_category'.split()
    writer = csv.DictWriter(file, delimiter='\t', fieldnames=FIELDNAMES)
    writer.writeheader()
    writer.writerows(dict(zip(FIELDNAMES, row))
                         for row in zip(*(my_data[key] for key in FIELDNAMES)))

正如您所看到的那样,两者的代码量大致相同,尽管第一个非DictWriter 版本效率更高一些,因为为每个row 生成数据需要的工作量更少,因此可能有点快点。

无论使用哪种类型的编写器,创建的test.tsv文件的内容都将完全相同,如下所示(其中代表制表符分隔符):

name→city→state→stars→review_count→main_category
Southern California Medical Group→Los Angeles→CA→3.5→2→Medical Centers
Harvard Square Shiatsu→Cambridge→MA→4.0→4→Massage
Faith & Glory Collective→Kitchener→ON→4.0→2→Tattoo

注意:如果您使用的是 Python 2,则打开输出文件以使用模式 'wb' 进行写入。对于 Python 2,您应该使用模式 'w' 并添加 newline='' 关键字参数。

【讨论】:

  • 非常感谢!除了缺少数据的第一行外,效果很好。我想我应该从 range(0,..)
  • 不客气,对需要更改的range() 的调用是正确的。之所以如此,是因为我错误地重建了my_data 的内容(因为您的问题中显示的内容不足以用于测试目的)。我建议您在发布任何其他问题之前阅读How to create a Minimal, Complete, and Verifiable example
  • 更新了答案,因此不再需要使用range()。还展示了如何使用 csv.DictWritercsv.writer 对象来做到这一点。
【解决方案3】:

如果每行的字段都有字典,请使用 DictWriter。它可以选择填充缺失字段的默认值,或者忽略输出中不需要的额外字段。

例子:

import csv

# Sample data converted to a list of lines.
datalines = '''\
Los Angeles,2,Southern California Medical Group,Medical Centers,CA,3.5
Cambridge,4,Harvard Square Shiatsu,Massage,MA,4.0
Kitchener,2,Faith & Glory Collective,Tattoo,ON,4.0
'''.splitlines()

# Specify the fields you want in the output.
# If your dictionaries have fields you don't want in the output, use extrasaction='ignore'
fields = 'name city state stars review_count main_category'.split()

# Python 3, use newline=''.  Python 2 use 'wb' instead.
with open('test.tsv','w',newline='') as file:
    writer = csv.DictWriter(file, fields, delimiter='\t', extrasaction='ignore')

    writer.writeheader() # Writes headers specified by "fields"

    for line in datalines:
        # Converts input line into a dict in OP's format.
        my_data = dict(zip('city review_count name main_category state stars'.split(),line.split(',')))
        print(my_data)
        writer.writerow(my_data)

验证字典的输出是 OP 的格式:

{'stars': '3.5', 'review_count': '2', 'name': 'Southern California Medical Group', 'city': 'Los Angeles', 'state': 'CA', 'main_category': 'Medical Centers'}
{'stars': '4.0', 'review_count': '4', 'name': 'Harvard Square Shiatsu', 'city': 'Cambridge', 'state': 'MA', 'main_category': 'Massage'}
{'stars': '4.0', 'review_count': '2', 'name': 'Faith & Glory Collective', 'city': 'Kitchener', 'state': 'ON', 'main_category': 'Tattoo'}

输出到 test.tsv(→ 用于选项卡):

name→city→state→stars→review_count→main_category
Southern California Medical Group→Los Angeles→CA→3.5→2→Medical Centers
Harvard Square Shiatsu→Cambridge→MA→4.0→4→Massage
Faith & Glory Collective→Kitchener→ON→4.0→2→Tattoo

【讨论】:

    猜你喜欢
    • 2019-07-20
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 2021-08-03
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多