使用csv从dict写入多行

时间:2016-09-28 21:02:44

标签: python csv

更新:我不想使用awk,因为我有一个dict列表,并且想要在每次进入磁盘时将其写入磁盘(webscraping的一部分)工作流程)。

我有一个dict,我想写一个csv文件。我已经提出了解决方案,但我想知道是否有更多pandas解决方案可用。这是我设想的(但不起作用):

pythonic

理想情况下会产生以下结果:

import csv
test_dict = {"review_id": [1, 2, 3, 4],
             "text": [5, 6, 7, 8]}

with open('test.csv', 'w') as csvfile:
    fieldnames = ["review_id", "text"]
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(test_dict)

上面的代码似乎并没有像我预期的那样工作并抛出一个值错误。所以,我转向了以下解决方案(这确实有效,但看起来很冗长)。

review_id text
        1    5
        2    6
        3    7
        4    8 

再一次,重申我正在寻找的东西:直接在上面的代码块工作(即产生在帖子中提到的期望结果),但似乎很冗长。那么,还有更多的with open('test.csv', 'w') as csvfile: fieldnames = ["review_id", "text"] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() response = test_dict cells = [{x: {key: val}} for key, vals in response.items() for x, val in enumerate(vals)] rows = {} for d in cells: for key, val in d.items(): if key in rows: rows[key].update(d.get(key, None)) else: rows[key] = d.get(key, None) for row in [val for _, val in rows.items()]: writer.writerow(row) 解决方案吗?

谢谢!

6 个答案:

答案 0 :(得分:1)

您的第一个示例将适用于少量编辑。 DictWriter预计会list dict而不是dict list。假设您无法更改test_dict的格式:

import csv
test_dict = {"review_id": [1, 2, 3, 4],
             "text": [5, 6, 7, 8]}

def convert_dict(mydict, numentries):
    data = []
    for i in range(numentries):
        row = {}
        for k, l in mydict.iteritems():
            row[k] = l[i]
        data.append(row)
    return data

with open('test.csv', 'w') as csvfile:
    fieldnames = ["review_id", "text"]
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(convert_dict(test_dict, 4))

答案 1 :(得分:0)

如果您不介意使用第三方软件包,可以使用pandas进行此操作。

import pandas as pd
pd.DataFrame(test_dict).to_csv('test.csv', index=False)

<强>更新

所以,你有几本词典,而且所有这些词典似乎来自一个刮擦程序。

import pandas as pd

test_dict = {"review_id": [1, 2, 3, 4],
             "text": [5, 6, 7, 8]}
pd.DataFrame(test_dict).to_csv('test.csv', index=False)

list_of_dicts = [test_dict, test_dict]
for d in list_of_dicts:
    pd.DataFrame(d).to_csv('test.csv', index=False, mode='a', header=False)

这次,您将附加到文件而没有标题。

输出结果为:

review_id,text
1,5
2,6
3,7
4,8
1,5
2,6
3,7
4,8
1,5
2,6
3,7
4,8

答案 2 :(得分:0)

尝试使用python的pandas ..

这是一个简单的例子

import pandas as pd
test_dict = {"review_id": [1, 2, 3, 4],
         "text": [5, 6, 7, 8]}
d1 = pd.DataFrame(test_dict)
d1.to_csv("output.csv")

干杯

答案 3 :(得分:0)

内置的zip function可以将不同的迭代连接到元组中,这些元组可以传递给writerows。试试这个作为最后一行:

writer.writerows(zip(test_dict["review_id"], test_dict["text"]))

您可以通过列表查看它的作用:

>>> list(zip(test_dict["review_id"], test_dict["text"]))
[(1, 5), (2, 6), (3, 7), (4, 8)]

修改:在这种特殊情况下,您可能需要常规csv.Writer,因为您实际拥有的是现在的列表。

答案 4 :(得分:0)

问题在于DictWriter.writerows()你被迫每行都有一个字典。相反,您只需添加更改csv创建的值:

with open('test.csv', 'w') as csvfile:
     fieldnames = test_dict.keys()
     fieldvalues = zip(*test_dict.values())

     writer = csv.writer(csvfile)
     writer.writerow(fieldnames)
     writer.writerows(fieldvalues)

答案 5 :(得分:0)

您的问题中有两个不同的问题:

  1. 从字典创建一个csv文件,其中值是容器而不是基元。
  2. 对于第一个问题,解决方案通常是将容器类型转换为基本类型。最常用的方法是创建一个json-string。例如:

    >>> import json
    >>> x = [2, 4, 6, 8, 10]
    >>> json_string = json.dumps(x)
    >>> json_string
    '[2, 4, 6, 8, 10]'
    

    因此,您的数据转换可能如下所示:

    import json
    
    
    def convert(datadict):
        '''Generator which converts a dictionary of containers into a dictionary of json-strings.
    
        args:
            datadict(dict): dictionary which needs conversion
    
        yield:
            tuple: key and string
        '''
        for key, value in datadict.items():
            yield key, json.dumps(value)
    
    
    def dump_to_csv_using_dict(datadict, fields=None, filepath=None, delimiter=None):
        '''Dumps a datadict value into csv
    
        args:
            datadict(list): list of dictionaries to dump
            fieldnames(list): field sequence to use from the dictionary [default: sorted(datadict.keys())]
            filepath(str): filepath to save to  [default: 'tmp.csv']
            delimiter(str): delimiter to use in csv [default: '|']
        '''
        fieldnames = sorted(datadict.keys()) if fields is None else fields
        filepath = 'tmp.csv' if filepath is None else filepath
        delimiter = '|' if not delimiter else delimiter
        with open(filepath, 'w') as csvfile:
           writer = csv.DictWriter(csvfile, fieldnames, restval='', extrasaction='ignore', delimiter=delimiter)
           writer.writeheader()
           for each_dict in datadict:
               writer.writerow(each_dict)
    

    所以天真转换看起来像这样:

    # Conversion code
    test_data = {
        "review_id": [1, 2, 3, 4],
             "text": [5, 6, 7, 8]}
    }
    
    converted_data = dict(convert(test_data))
    data_list = [converted_data]
    dump_to_csv(data_list)
    
    1. 创建一个最终值,实际上是两种不同数据集的合并。
    2. 为此,您需要找到一种方法来组合来自不同键的数据。这通常不是一个容易解决的问题。

      也就是说,将两个列表与zip结合起来很容易。

      >>> x = [2, 4, 6]
      >>> y = [1, 3, 5]
      >>> zip(y, x)
      [(1, 2), (3, 4), (5, 6)]
      

      此外,如果您的列表大小不同,python的itertools包提供了一个方法izip_longest,即使一个列表比另一个列表短,也会返回完整的zip。注意izip_longest返回一个生成器。

      from itertools import izip_longest
      >>> x = [2, 4]
      >>> y = [1, 3, 5]
      >>> z = izip_longest(y, x, fillvalue=None)  # default fillvalue is None
      >>> list(z)  # z is a generator
      [(1, 2), (3, 4), (5, None)]
      

      所以我们可以在这里添加另一个函数:

      from itertoops import izip_longest
      
      def combine(data, fields=None, default=None):
          '''Combines fields within data
      
          args:
              data(dict): a dictionary with lists as values
              fields(list): a list of keys to combine [default: all fields in random order]
              default: default fill value [default: None]
          yields:
              tuple: columns combined into rows
          '''
          fields = data.keys() if field is None else field
          columns = [data.get(field) for field in fields]
          for values in izip_longest(*columns, fillvalue=default):
              yield values
      

      现在我们可以使用它来更新我们的原始转换。

      def dump_to_csv(data, filepath=None, delimiter=None):
          '''Dumps list into csv
      
          args:
              data(list): list of values to dump
              filepath(str): filepath to save to  [default: 'tmp.csv']
              delimiter(str): delimiter to use in csv [default: '|']
          '''
          fieldnames = sorted(datadict.keys()) if fields is None else fields
          filepath = 'tmp.csv' if filepath is None else filepath
          delimiter = '|' if not delimiter else delimiter
          with open(filepath, 'w') as csvfile:
             writer = csv.writer(csvfile, delimiter=delimiter)
             for each_row in data:
                 writer.writerow(each_dict)
      
      # Conversion code
      test_data = {
          "review_id": [1, 2, 3, 4],
               "text": [5, 6, 7, 8]}
      }
      
      combined_data = combine(test_data)
      data_list = [combined_data]
      dump_to_csv(data_list)