【问题标题】:Python: Removing duplicate tuples in 2 csv filesPython:删除 2 个 csv 文件中的重复元组
【发布时间】:2020-01-08 17:58:16
【问题描述】:

我有 2 个包含已排序整数元组的 csv 文件

旧文件.csv

"(1, 2, 3)","(1, 2, 4)","(1, 3, 5)"

新文件.csv

"(1, 2, 3)","(1, 2, 4)"

我想删除这两个 csv 文件之间的 common tuples 并将输出打印为 final.csv

预期输出

"(1,3,5)"

代码尝试 A

import csv

with open('old file.csv', newline ='') as myFile_1:  
    reader = csv.reader(myFile_1)
    list_a = list(reader)
    older = [tuple(map(int, i)) for i in list_a]

with open('new file.csv', newline ='') as myFile_2:  
    reader = csv.reader(myFile_2)
    list_b = list(reader)
    newer = [tuple(map(int, i)) for i in list_b]

final_output = older.difference(newer)

csvData = [final_output]

with open('final.csv', 'w') as csvFile:
    writer = csv.writer(csvFile)
    writer.writerows(csvData)

csvFile.close()

错误类型

Exception has occurred: ValueError
invalid literal for int() with base 10: '(1, 2, 3)'

代码尝试 B

import csv

with open('old file.csv', newline ='') as myFile_1:  
    reader = csv.reader(myFile_1)
    list_a = list(reader)
    older = [tuple(map(str, i)) for i in list_a]

with open('new file.csv', newline ='') as myFile_2:  
    reader = csv.reader(myFile_2)
    list_b = list(reader)
    newer = [tuple(map(str, i)) for i in list_b]

final_output = older.difference(newer)

csvData = [final_output]

with open('final.csv', 'w') as csvFile:
    writer = csv.writer(csvFile)
    writer.writerows(csvData)

csvFile.close() 

错误类型

Exception has occurred: AttributeError
'list' object has no attribute 'difference'

当我想操作 csv 文件时出现此问题,并且当 old.csv 和 new.csv 中包含的数据在运行程序时生成并存储为变量时工作得很好。这在生成较小的数据集时效果很好,但在生成大型数据集时会出现问题。

【问题讨论】:

  • 顺序重要吗?这是双重的。 (1, 2, 4) 与 (2, 1, 4) 不同吗?最终列表中出现的顺序 (1, 2, 4) 和 (3, 5, 7) 是否重要?
  • 是的,订单很重要。 (1,2,4) 是一个单独的元组, (2,1,4) 是一个单独的元组。原始元组文件是通常按升序 (1,2,4) 或降序 (4,2,1) 顺序排列的有序元组,我想保持相同。在任何情况下,我都不会对具有相反顺序值的两个文件进行比较
  • 最终列表中出现的顺序 (1,2,4) 和 (3,5,7) 无关紧要。但是,我可以通过编写函数来根据元组的索引对元组的外观进行排序。
  • 也许这对你有帮助:stackoverflow.com/questions/3462143/…。使用集合而不是列表

标签: python csv duplicates tuples


【解决方案1】:

我实际上建议更改数据存储策略,而不是将原始数据结构表示形式保存到 csv 文件中。
但是,如果您不允许影响这些事情 - 请使用以下简短方法:

import csv
from ast import literal_eval

with open('old_file.csv', newline ='') as f1, open('new_file.csv', newline ='') as f2:
    t1 = literal_eval('{{{}}}'.format(f1.read().replace('"', '')))
    t2 = literal_eval('{{{}}}'.format(f2.read().replace('"', '')))

    final_output = t1 - t2

with open('final.csv', 'w') as csv_result:
    writer = csv.writer(csv_result, delimiter=',', quotechar='"')
    writer.writerow(final_output)
  • literal_eval('{...}' - 允许一次获取一组元组,用 set 对象文字 {} 包装传递的参数

最终的final.csv文件内容:

"(1, 3, 5)"

【讨论】:

  • 您如何看待 OP 对大型数据集的关注? Python 集真的比在将数据存储在 csv 文件中之前使用的任何方法都更有效吗?
【解决方案2】:

假设您可以按照上面的建议更改输入文件的格式,例如使用 shell 命令

cat file.csv | sed 's/",/"\n/g' > file.txt

每行一个元组,允许您处理更大文件的解决方案是:

import itertools as it

diff = set()
with open('old_file.txt') as f1, open('new_file.txt') as f2:
    ts = it.chain(f1, f2)
    for t in ts:
        t2 = t.rstrip()  # remove the newline
        try:
            diff.remove(t2)
        except KeyError:
            diff.add(t2)

print(diff)

生产

{'"(1, 3, 5)"'}

注意:diff 是一个集合,其中包含作为字符串的元组,即原始格式,因为这是您指定的输出。使用集合是因为​​它可以快速检查元素是否存在。

基本上是一个一个一个文件一个一个地遍历每个值,然后删除每个元素。如果该值尚不存在,则将其添加到差异中。

只有想要的差异会在内存中增长,每个文件都只是简单地迭代而不创建列表。

但是,如果元组可以在每个文件中出现多次,我们必须跟踪它们的来源。扫描值后,我们过滤结果并仅保留出现在一个文件中的结果。

例如像这样的输入

(m37) ➜  SO cat old_file.txt      
"(1, 2, 3)"
"(1, 2, 4)"
"(1, 2, 4)"
"(1, 3, 5)"
(m37) ➜  SO cat new_file.txt      
"(1, 2, 3)"
"(3, 7, 9)"
"(1, 2, 4)"
"(3, 7, 9)"
"(1, 2, 3)"

这段代码

from collections import defaultdict
import itertools as it

diff = defaultdict(set)
with open('old_file.txt') as f1, open('new_file.txt') as f2:
    ts = it.chain(zip(f1, it.repeat(1)), zip(f2, it.repeat(2)))
    for t, fi in ts:
        t2 = t.rstrip()
        diff[t2].add(fi)

final_diff = (t for t, fs in diff.items() if len(fs) == 1)
print(list(final_diff))

生产

['"(1, 3, 5)"', '"(3, 7, 9)"']

注意:可以轻松更改代码以适应任意数量的文件,而不仅仅是两个。

【讨论】:

  • @user7970547 这个解决方案最接近原始帖子,包括处理大型数据集
  • @Pynchia 更改文件格式会很困难,但是我可以将文件生成为 .csv 或 .xlsx 或 .txt。我是否必须将每个元组生成为换行符 (/n) 才能使代码正常运行?
  • 如果您不能用换行符分隔元组,请按照您的描述保留文件并使用我展示的 sed 命令转换它们。或者,考虑this QA
  • @Pynchia 有没有办法在 Windows 中使用命令提示符进行转换?从一个系统到另一个系统的转换变得非常棘手。
  • 解决方案是在我寻找“设置差异”时合并文件。删除旧文件中包含的新文件的所有元素。
【解决方案3】:

这是我的结果:

tuple_1_list = open('test_tuple_1.csv', 'r').read().splitlines()
tuple_2_list = open('test_tuple_2.csv', 'r').read().splitlines()

tuple_1_list = list(map(lambda x: tuple(x.replace('\'', '').replace('\"', '')[1:-1].split(', ')), tuple_1_list))
tuple_2_list = list(map(lambda x: tuple(x.replace('\'', '').replace('\"', '')[1:-1].split(', ')), tuple_2_list))

output_set = set()

for i in tuple_1_list:
    output_set.add(i)

for i in tuple_2_list:
    output_set.add(i)

for i in tuple_1_list:
    if i in tuple_2_list and i in output_set:
        output_set.remove(i)

for i in tuple_2_list:
    if i in tuple_1_list and i in output_set:
        output_set.remove(i)

with open('test_tuple_out.csv', 'w+') as out_file:
    for output in output_set:
        out_file.write('\"' + str(output).replace('\'', '').replace(', ', ',') + '\"')

我能够通过您的输入 CSV 获得您预期的输出。希望这对你有用。

【讨论】:

    猜你喜欢
    • 2022-10-21
    • 2020-05-19
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多