【问题标题】:change order of columns in csv (python)更改csv中列的顺序(python)
【发布时间】:2015-10-07 15:22:39
【问题描述】:

我编写了一个脚本,它读取给定的输入文件 (csv),以某种方式处理数据并写入输出文件 (csv)。

就我而言,我给定的输入文件如下所示:

| sku | article_name |
| 1   | MyArticle    |

对于我的输出文件,我需要重新排列这些列(还有很多,但我想我可能能够解决它,当有人给我指路时)

我的输出文件应该是这样的:

| article_name | another_column | sku |
| MyArticle    |                | 1   |

注意,这是一个新列,不在源 csv 文件中,但无论如何都必须打印(顺序也很重要)

这是我目前所拥有的:

#!/usr/bin/env python
# -*- coding: latin_1 -*-

import csv
import argparse
import sys


header_mappings = {'attr_artikel_bezeichnung1': 'ARTICLE LABEL',
                   'sku': 'ARTICLE NUMBER',
                   'Article label locale': 'Article label locale',
                   'attr_purchaseprice': 'EK-Preis',
                   'attr_salesPrice': 'EuroNettoPreis',
                   'attr_salesunit': 'Einheit',
                   'attr_salesvatcode': 'MwSt.-Satz',
                   'attr_suppliercode': 'Lieferantennummer',
                   'attr_suppliersitemcode': 'Artikelnummer Lieferant',
                   'attr_isbatchitem': 'SNWarenausgang'}

row_mapping = {'Einheit': {'pc': 'St.'},
               'MwSt.-Satz': {'3': '19'}}


def remap_header(header):
    for h_map in header_mappings:
        if h_map in header:
            yield header_mappings.get(h_map), header.get(h_map)


def map_header(header):
    for elem in header:
        yield elem, header.index(elem)


def read_csv(filename):
    with open(filename, 'rb') as incsv:
        csv_reader = csv.reader(incsv, delimiter=';')
        for r in csv_reader:
            yield r


def add_header(header, fields=()):
    for f in fields:
        header.append(f)

    return header


def duplicate(csv_row, header_name, fields):
    csv_row[new_csv_header.index(fields)] = csv_row[new_csv_header.index(header_name)]
    return csv_row


def do_new_row(csv_row):
    for header_name in new_csv_header:
        for r_map in row_mapping:
            row_content = csv_row[mapped_header.get(r_map)]
            if row_content in row_mapping.get(r_map):
                csv_row[mapped_header.get(r_map)] = row_mapping.get(r_map).get(row_content)
        try:
            yield csv_row[mapped_header.get(header_name)]
        except TypeError:
            continue


if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--infile', metavar='CSV')
    parser.add_argument('-o', '--outfile', metavar='CSV')

    args = parser.parse_args()
    arguments = vars(args)
    if len(sys.argv[1:]) == 0:
        parser.print_usage()
        sys.exit(0)

    # print arguments
    # parse_csv(**arguments)
    """
    """
    csv_reader_iter = read_csv(arguments.get('infile'))

    # neuer csv header
    new_csv_header = list()
    csv_header = next(csv_reader_iter)
    for h in csv_header:
        if h in header_mappings:
            new_csv_header.append(header_mappings.get(h))

    # print new_csv_header
    new_csv_header = add_header(new_csv_header, ('Article label locale', 'Nummer'))
    mapped_header = dict(remap_header(dict(map_header(csv_header))))
    # print mapped_header

    with open(arguments.get('outfile'), 'wb') as outcsv:
        csv_writer = csv.writer(outcsv, delimiter=';')
        csv_writer.writerow(new_csv_header)
        for row in csv_reader_iter:
            row = list(do_new_row(row))
            delta = len(new_csv_header) - len(row)
            if delta > 0:
                row = row + (delta * [''])

            # duplicate(row, 'SNWarenausgang', 'SNWareneingang')
            # duplicate(row, 'SNWarenausgang', 'SNWareneingang')
            csv_writer.writerow(row)


    print "Done."
    """
    print new_csv_header
    for row in csv_reader_iter:
        row = list(do_new_row(row))
        delta = len(new_csv_header) - len(row)
        if delta > 0:
            row = row + (delta * [''])

        duplicate(row, 'Herstellernummer', 'Nummer')
        duplicate(row, 'SNWarenausgang', 'SNWareneingang')
        print row
    """

现在,即使它先显示“ARTICLE LABEL”,也会先打印 sku。我的猜测:这是由于 csv 文件的顺序,因为 sku 是那里的第一个字段......对吗?

【问题讨论】:

    标签: python csv


    【解决方案1】:

    如果您使用来自csv 库的DictWriter,您可以指定列的顺序。使用DictReader 从文件中读取行作为字典。然后,您只需在创建 DictWriter 时明确指定键的顺序。

    https://docs.python.org/2/library/csv.html#csv.DictReader

    【讨论】:

    • 我需要调整“do_new_row”功能吗?对不起,我只是习惯了 PHP =(
    • 如果可能的话,你能给我看一个关于我的代码的例子吗?这个 DictWriter 应该在哪里?
    • 您想用csv.DictReader 替换csv.reader,用csv.DictWriter 替换csv.writer。我提供的链接有使用这些的示例。您将不得不修改您的代码,因为您现在将使用 dicts 而不是 lists
    • 我试图用您的解决方案替换 csv.reader,但最终出现错误(正如您已经告诉我的,因为我使用的是字典而不是列表。我可以寻求进一步的帮助吗?
    【解决方案2】:

    正如 riotburn 已经建议的那样,您可以使用 DictWriter 及其 fieldnames 参数来调整新文件中列的顺序。

    重新排序文件可能如下所示:

    def read_csv (filename):
        with open(filename) as incsv:
           reader = csv.DictReader(incsv, delimiter=';')
           for r in reader:
               yield r
    
    columns = ['article_name', 'another_column', 'sku']
    
    with open('newfile.csv', 'w+') as f:
        writer = csv.DictWriter(f, columns, delimiter=';')
        writer.writeheader()
    
        for row in read_csv('oldfile.csv'):
            # add a property
            row['another_column'] = 'foo'
    
            # write row (using the order specified in columns)
            writer.writerow(row)
    

    【讨论】:

      猜你喜欢
      • 2021-09-23
      • 1970-01-01
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-07
      • 1970-01-01
      相关资源
      最近更新 更多