2016-09-28 40 views
0

更新:我不想使用pandas,因为我有一个dict's列表,并且希望在进入磁盘时将它们写入磁盘(网络扫描工作流的一部分)。使用csv从字典中写入多行

我有一个字典,我想写入一个csv文件。我想出了一个解决方案,但我想知道是否有更多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) 

再次重申我正在寻找:直接工程上方(即产生在后早期提到的期望的结果)的代码块,但似乎冗长。那么,有没有更多的pythonic解决方案?

谢谢!

+1

我相信'DictWriter'需要一个'dict'列表而不是'list'的'dict'列表。在这里看到的例子:https://docs.python.org/2/library/csv.html#csv.DictWriter – FamousJameous

回答

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 
+0

我没有使用'原因pandas'是因为遍历多个词典(test_dict的列表)和我想将每个行写入磁盘。 –

+0

@RyanErwin但都在同一个'test.csv'文件? – gabra

+0

是的,所以假设它们与test_dict的大小相同,相同的键和不同的值,则每个都会添加四个新行。 –

0

尝试使用python的大熊猫..

下面是一个简单的例子

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") 

干杯

+0

我不使用'pandas'的原因是因为循环了多个字典(test_dict的列表),我想将每行写入磁盘。 –

+0

是否有类似的词典列表: [{'review_id':[1,2,3,4],'text':[5,6,7,8]},{'review_id2':[ 1,2,3,4],'text2':[5,6,7,8]}] 并且您希望通过review_id创建一个csv作为列1,文本作为col2等等。 ??我对吗 ? –

1

你的第一个例子将未成年人工作编辑。 DictWriter预计listdict s而不是listdict s。假设你不能改变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)) 
0

内置zip function可以一起加入不同iterables成可以传递给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,因为什么你现在有一个列表。

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) 
+0

该示例依赖字典迭代顺序。 –

0

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

  1. 从字典其中的值是容器,而不是原语创建一个CSV文件。

对于第一个问题,解决方案通常是将容器类型转换为基本类型。最常用的方法是创建一个json字符串。因此,例如:

>>> 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) 
  • 创建一个实际上是两种不同数据集的某种合并的最终值。
  • 要做到这一点,您需要找到一种方法来组合来自不同键的数据。这通常不是一个容易解决的问题。

    这就是说,它很容易两个清单合并拉链。

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

    此外,在事件你的列表是不一样的大小,python的itertools包提供了一个方法,izip_longest,这将产生回全拉链即使一个列表比另一个短。注意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)