通过元组名称将不同命名元组的列表传递给不同的csv

时间:2015-10-20 15:05:48

标签: python csv namedtuple

我有一个程序,我希望记录所有发生的重大变化。例如:每次变量x值的变化都会记录变更的时间和变化本身。在程序中有许多这样的变化,并不是都具有相同数量的参数。

我决定使用namedtuples来存储每个更改实例,然后将这些命名元素放入一个主数据列表中 - 已经导出到csv。我使用元组当然它们是不可变的,这是记录保存的理想选择。下面我试着以尽可能简洁的方式解释我所做的和尝试过的事情。希望到目前为止,我的问题和尝试都是明确的。

所以我有:

data = [] 

作为主存储库,其格式为:

a_tuple = namedtuple('x_change', ['Time', 'Change'])
another_tuple = namedtuple('y_change', ['Time', 'Change', 'id'])

每次使用以下命令检测到数据更改时,我都可以追加这些命名元组的实例:

data.append(a_tuple(a_time, a_change))
data.append(another_tuple(a_time, a_change, an_id))

如果我打印出数据内容,我会得到如下输出:

x_change(a_time=4, a_change=1)
y_change(a_time=5, a_change=3, an_id = 2)
y_change(a_time=7, a_change=1, an_id = 3)
x_change(a_time=8, a_change=3)

我想要做的是通过元组名称将这些元组导出到csv文件。所以在上面的例子中,我最终得到了两个形式的csv文件:

name, time, change
x_change, 4, 1
x_change, 8, 3

name, time, change, id
y_change, 5, 3, 2
y_change, 7, 1, 3

我必须设法写一个单独的csv,如下所示:

with open ('events.csv', 'w', newline='') as csvfile:
    output = csv.writer(csvfile, delimiter = ',')
    for row in data:
        output.writerow(row)

产生输出减去元组名称。所以:

4, 1
5, 3, 2
7, 1, 3
8, 3

我也尝试过:

with open ('events.csv', 'w', newline='') as csvfile:
    output = csv.writer(csvfile, delimiter = ',')
    for row in data:
        output.writerow(str(row))

将文件拆分为csv格式,包括元组名称,每个字符获取(仅包括第一行):

x, _, c, h, a, n, g, e, 4, 1

我已经找到了一个解决方案,但没有遇到任何适合我想要做的事情,现在我不知所措。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:1)

以下方法应该有效。这将使您的数据包含所有已命名的元组,并首先按元组的类型对其进行排序。然后,它会对所有条目进行分组,并为每个条目创建一个CSV文件。每个CSV文件中的第一行包含字段名称:

from collections import namedtuple
from itertools import groupby
import csv

data = [] 

a_tuple = namedtuple('x_change', ['Time', 'Change'])
another_tuple = namedtuple('y_change', ['Time', 'Change', 'id'])

data.append(a_tuple(6, 1))
data.append(a_tuple(2, 1))
data.append(another_tuple(5, 3, 2))
data.append(another_tuple(7, 1, 3))
data.append(a_tuple(5, 2))

data.sort(key=lambda x: type(x).__name__)

for k, g in groupby(data, lambda x: type(x).__name__):
    with open('{}.csv'.format(k), 'w', newline='') as f_output:
        csv_output = csv.writer(f_output)
        rows = list(g)
        csv_output.writerow(['Name'] + list(rows[0]._fields))
        for row in rows:
            csv_output.writerow([type(row).__name__] + list(row))

对于我的数据,这将为您提供两个CSV文件,如下所示:

<强> x_change.csv

Name,Time,Change
x_change,6,1
x_change,2,1
x_change,5,2

<强> y_change.csv

Name,Time,Change,id
y_change,5,3,2
y_change,7,1,3

答案 1 :(得分:0)

查看namedtuple实例表示 - __repr__

>>>import namedtuple

>>>Row = namedtuple('Row', 'time, change')
>>>record = Row(4, 1)

...

>>>help(record)
class Row(builtins.tuple)
 |  Row(time, change)
 |
 |  Method resolution order:
 |      Row
 |      builtins.tuple
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __getnewargs__(self)
 |      Return self as a plain tuple.  Used by copy and pickle.
 |
 |  __getstate__(self)
 |      Exclude the OrderedDict from pickling
 |
 |  __repr__(self)
 |      Return a nicely formatted representation string
 |
 |  _asdict(self)
 |      Return a new OrderedDict which maps field names to their values.
 |
...


>>> record.__repr__()
'Row(time=4, change=1)'
>>> repr(record)
'Row(time=4, change=1)'

从那里你可能需要做一些解析,但它是一个很好的起点,因为namedtuple名称存在。

希望这会有所帮助。

答案 2 :(得分:0)

通过在namedtuple中将名称设为字段,可以让您的生活更轻松。

xChange = namedtuple('xChange', ['name', 'time' 'change'])
yChange = namedtuple('yChange', ['name', 'time', 'change', 'id'])

namedtuple没有默认值,但您可以将xChange子类化,例如,创建一个在__init__

中将名称设置为'x_change'的namedtuple

答案 3 :(得分:0)

您需要完成两件事:

  1. 将类型名称添加到行
  2. 为每个元组类型创建一个文件
  3. 对于#1,创建一个函数来返回你真正想要的行。

    def get_row_output(row):
        return [type(row).__name__] + list(row)
    

    (命名元组最终创建一个以namedtuple()的第一个参数值命名的自定义类型。该名称不会使其成为该类型实例数据的任何表示形式,因此您有自己提取它。)

    对于#2,要以不同的文件结束,您需要在写出CSV的代码之外循环数据。最简单的方法:

    for row in data:
        with open(row.__name__ + '.csv', 'a+') as csvfile:
            output = csv.writer(csvfile, delimiter=',')
            output.writerow(get_row_output(row))
    

    (注意在附加模式下打开文件,因为您在每行上打开和关闭文件。)

    如果data非常大,那么最好不要打开文件句柄而不是每行打开和关闭。类似的东西:

    def get_filename(row):
        return row.__name__ + '.csv'
    
    def write_changes(data):
        file_handles = {}
        csv_writers = {}
    
        for row in data:
            filename = get_filename(row)
            if filename not in file_handles:
                f = open(filename, 'wb')
                file_handles[filename] = f
                csv_writer = csv.writer(f, delimiter=',')
                csv_writers[filename] = csv_writer
    
            csv_writers[filename].writerow(get_row_output(row))
    
        for f in file_handles.values():
            f.close()