在 Python 中连接具有相同第一列值的 CSV 文件的所有行

Posted

技术标签:

【中文标题】在 Python 中连接具有相同第一列值的 CSV 文件的所有行【英文标题】:Joining all rows of a CSV file that have the same 1st column value in Python 【发布时间】:2012-06-17 09:52:31 【问题描述】:

我有一个类似这样的 CSV 文件:

['Name1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '+'] ['Name1', '', '', '', '', '', 'b', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] ['Name2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '一种', ''] ['Name3', '', '', '', '', '+', '', '', '', '', '', '', '', '' , '', '', '', '', '', '', '']

现在,我需要一种方法将具有相同第一列名称的所有行合并为一列,例如:

['Name1', '', '', '', '', '', 'b', '', '', '', '', '', '', '', '' , '', '', '', '', '', '+'] ['Name2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '一种', ''] ['Name3', '', '', '', '', '+', '', '', '', '', '', '', '', '' , '', '', '', '', '', '', '']

我可以想办法做到这一点,对 CSV 进行排序,然后遍历每一行和每一列并比较每个值,但应该有更简单的方法。

有什么想法吗?

【问题讨论】:

这听起来是最合乎逻辑的做法。 您可能应该更明确地了解 join 应该做什么。 同一列是否可以存在于具有相同第一个值的两行中?在这种情况下你想做什么? @moooeeeep:好吧,我想加入他们,让他们就像示例的第二部分一样。 @CharlesBrunet:不,对于同名,每列的值只能在其他列之一中出现一次。 【参考方案1】:

你应该使用 itertools.groupby:

t = [ 
['Name1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '+'],
['Name1', '', '', '', '', '', 'b', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
['Name2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'a', ''],
['Name3', '', '', '', '', '+', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] 
]

from itertools import groupby

# TODO: if you need to speed things up you can use operator.itemgetter
# for both sorting and grouping
for name, rows in groupby(sorted(t), lambda x:x[0]):
    print join_rows(rows)

很明显,您将在单独的函数中实现合并。比如这样:

def join_rows(rows):
    def join_tuple(tup):
        for x in tup:
            if x: 
                return x
        else:
            return ''
    return [join_tuple(x) for x in zip(*rows)]

【讨论】:

它不起作用。它是 join_rows 来自某个库的函数还是我必须在代码之外编写的东西? @jbssm join_rows 是您的代码的入口点,它是由您编写的;) @moooeeeep 不要在没有密钥的情况下使用sorted,这是不必要的运行时间。 @moooeeeep itemgetter(0) 会是更好的方法(见***.com/a/4174955/851737) 所以它看起来像:for name, rows in groupby(sorted(t, key=itemgetter(0)), itemgetter(0))【参考方案2】:
def merge_rows(row1, row2):
    # merge two rows with the same name
    merged_row = ...
    return merged_row

r1 = ['Name1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '+']
r2 = ['Name1', '', '', '', '', '', 'b', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
r3 = ['Name2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'a', '']
r4 = ['Name3', '', '', '', '', '+', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
rows = [r1, r2, r3, r4]
data = 
for row in rows:
    name = row[0]
    if name in data:
        data[name] = merge_rows(row, data[name])
    else:
        data[name] = row

您现在拥有data 中的所有行,其中该字典的每个键是名称,对应的值是该行。您现在可以将此数据写入 CSV 文件。

【讨论】:

嗨,谢谢 Simeon:我不明白 merge_row 部分发生了什么。具有相同名称的前一行(或多行)存储在哪里以便我可以合并它们? 您正在处理的当前行是row,另一行是data[name]data[name] 中的行要么是具有该名称的前一行,要么是具有该名称的行的一个或多个合并的结果。因此,您只需要编写指定如何合并具有相同名称的两行的代码。如果您为merged_row 编写该代码,那么它将重复合并行(即使有三个或更多行具有相同的名称)。 我已经更新了代码,让它有点清晰。您需要做的就是写merge_rows 来指定如何合并两个同名的行。【参考方案3】:

你也可以使用defaultdict:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> _ = [d[i[0]].append(z) for i in t for z in i[1:]]
>>> d['Name1']
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '+', '', '', '', '', '', 'b', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

然后加入你的专栏

【讨论】:

以上是关于在 Python 中连接具有相同第一列值的 CSV 文件的所有行的主要内容,如果未能解决你的问题,请参考以下文章

SQL 查询以查找具有相同列值的多行

熊猫将具有相同索引的一列值组合到列表中[重复]

连接具有相同值的行的列值(不同列的)

mysql连接具有相同列值的两行并计算某些列值并返回一行中的所有行

如何在数据工厂中获取 CSV 的第一行和第一列值?

添加具有另一列值的 len() 的 DataFrame 列