如何根据给定列表中的单词合并两个csv文件?

问题描述 投票:0回答:3

我有两个csv文件,每个都是这种格式,

file1
zip     name    score                
23431   david   12                  
23231   rob     45
33441   hary    23
98901   rgrg    55  


file2
zip1    name1   score1                
23433   david   12                  
23245   stel    45
33478   hary    23
98988   rob     55  
12121   jass    33

我有一个名单,如下所示

lista = ['harry', 'rob', 'wine', 'david', 'jass']

最终的csv文件应该如下所示:

name    zip     score       zip1     score1
harry   x       x           x           x
rob     23231   45          98988       55
wine    x       x           x           x
david   23431   12          23433       12
jass    x       x           12121       33

这意味着,如果列表中的任何名称位于任何一个csv文件中,那么我们应该将它包含在新的csv文件中,以及它的zip和分数。否则我们应该在其中打印'x'。

这是我到目前为止所做的:

import csv
with open('file1.csv', 'r') as input1, open('file2.csv', 'r') as input2, open('merge_final.csv', 'w') as output:
    writer = csv.writer(output)
    reader1 = csv.reader(input1)
    eader2 = csv.reader(input2)

    lista = ['harry', 'rob', 'wine', 'david', 'jass']
    writer.writerow(['name','zip','score','zip1','score'])

        for i in lista:     
            for row in list(reader1):
                rev = row[1]
                if i in rev:
                    score = row[2]
                    zip = row[0]    
                else:
                    score = 'x'
                    zip = 'x'               
            for row in list(reader2):
                rev = row[1]
                if i in rev:
                    score1 = row[2]
                    zip1 = row[0]
                else:
                    score1 = 'x'
                    zip1 = 'x'  
            writer.writerow([i, score, zip, score1, zip1])

此代码未按预期工作。这是我使用此代码获得的输出。

name    zip     score       zip1     score1
harry   x       x           x           x
rob     x      x            x            x
wine    x       x           x           x
david   x       x           x           x
jass    x       x           x           x

即使认为有许多常见的单词,只有'x'才能在最终合并的csv文件中打印出来。我认为问题在于循环。但是,我似乎没有弄清楚这个问题。

python loops csv for-loop
3个回答
3
投票

首先,list(readerX)的第一次调用耗尽了文件句柄的迭代器。

其次,rev本来应该是name,所以检查平等不包含:if name == rev

第三,除了每个文件中的姓氏之外,你大多得到'x',因为你将文件迭代到最后,只有最后一行才真正重要。一旦找到名称,就应该break内部循环,但只有在迭代整个文件而没有找到名称后才设置默认值。

此外,重复迭代这两个文件在性能方面是非常糟糕的。您最好将两个文件加载到永久数据结构中,使用更快的查找,如名称为键的嵌套dict

d1 = {row[1]: {'zip': row[0], 'score': row[2]} for row in reader1}
d2 = {row[1]: {'zip': row[0], 'score': row[2]} for row in reader2}
#   {'david': {'zip': 23431, 'score: 12, ...}    

for name in lista:
    if name in d1 or name in d2:
        writer.writerow([
            name,
            d1.get(name, {}).get('zip', 'x'),
            d1.get(name, {}).get('score', 'x'),
            d2.get(name, {}).get('zip', 'x'),
            d2.get(name, {}).get('score', 'x'),
        ])

要使您自己的方法工作,请按以下方式进行更改,但请注意,由于嵌套循环,这对于较大的数据具有可怕的性能:

# next(reader1)  # skip the header line if necessary
lst1 = list(reader1)  # load all the data into a list beforehand ...
for i in lista:  
    for row in lst1:  # ... that you can repeatedly iterate
        rev = row[1]
        if i == rev:  # compare for equality
            score = row[2]
            zip = row[0]   
            break  # <- you found the name, so end the loop! 
    else:  # note the indentation: this is a for-else-loop, not an if-else
        # the else-part is only executed if the for loop was NOT break'ed
        score = 'x'
        zip = 'x'  

0
投票

您是否认为将两个文件读入单个嵌套字典会更好,其中名称将是键,值将是带有键'zip,'zip1','score'和'score1'的字典?

    {'hary' : 
        {'zip1':33478, 
         'zip':33441 ,
         'score':23,
         'score1':23 }
    }

然后遍历列表并打印“x”以查找不存在的键


0
投票

上面代码中的错误:

  1. 列表的第一个循环(reader1)耗尽了作为文件句柄的迭代器。因此,当'lista'的下一次迭代开始时,reader1为空,len = 0。 而不是重复迭代文件句柄存储列表或字典中的数据。
  2. 如果i与if匹配,则if(i in rev)你继续迭代文件的其余部分,导致zip和score的值重置为'x',如下一次迭代“i in rev”会给出错误的。你需要删除else部分来纠正这个问题。而是声明zip,在lista中为i分数为'x':
© www.soinside.com 2019 - 2024. All rights reserved.