【问题标题】:Comparing two CSV files in Python when rows have multiple values当行具有多个值时比较Python中的两个CSV文件
【发布时间】:2015-09-27 19:18:27
【问题描述】:

我有两个要比较的 CSV 文件,如下所示:

"a" 1   6   3   1   8
"b" 15  6   12  5   6
"c" 7   4   1   4   8
"d" 14  8   12  11  4
"e" 1   8   7   13  12
"f" 2   5   4   13  9
"g" 8   6   9   3   3
"h" 5   12  8   2   3
"i" 5   9   2   11  11
"j" 1   9   2   4   9

所以“a”拥有数字 1,6,3,1,8 等。实际的 CSV 文件有 1,000 行长,因此您在编写代码时为了提高效率而知道。

第二个 CSV 文件如下所示:

4

15

7

9

2

我已经编写了一些代码来将这些 CSV 文件导入 python 中的列表。

with open('winningnumbers.csv', 'rb') as wn:
    reader = csv.reader(wn)
    winningnumbers = list(reader)

wn1 = winningnumbers[0]
wn2 = winningnumbers[1]
wn3 = winningnumbers[2]
wn4 = winningnumbers[3]
wn5 = winningnumbers[4]

print(winningnumbers)

with open('Entries#x.csv', 'rb') as en:
    readere = csv.reader(en)
    enl = list(readere)

我现在如何使用第一个 csv 文件搜索 CSV 文件 2 的 wn1 的交叉引用号 4。这样它会返回“b”中包含 wn1。我将它们作为一个列表导入,看看我是否能弄清楚如何去做,但最后只是绕着圈子跑。我也尝试过使用 dict() 但没有成功。

【问题讨论】:

  • 不确定我是否遵循您的逻辑,wn1 应该是什么?
  • wn1(中奖号码 1)将是第二个 csv 文件中的第一个号码,因此它的值为 4。第一个列表值。
  • 那么你想找出哪些行包含特定的数字?
  • 但是b里面没有4?重复也很重要吗?
  • 你是对的,那是意外应该键入 C。重复无关紧要。

标签: python csv dictionary compare


【解决方案1】:

如果我对您的理解正确,您希望找到获胜条目中数字的第一个索引(或所有索引)。如果你愿意,你可以这样做:

with open('winningnumbers.csv', 'rb') as wn:
    reader = csv.reader(wn)
    winningnumbers = list(reader)

with open('Entries#x.csv', 'rb') as en:
    readere = csv.reader(en)
    winning_number_index = -1 # Default value which we will print if nothing is found
    current_index = 0 # Initial index
    for line in readere: # Iterate over entries file
        all_numbers_match = True # Default value that will be set to False if any of the elements doesn't match with winningnumbers
        for i in range(len(line)):
            if line[i] != winningnumbers[i]: # If values of current line and winningnumbers with matching indexes are not equal
                all_numbers_match = False # Our default value is set to False
                break # Exit "for" without finishing

        if all_numbers_match == True: # If our default value is still True (which indicates that all numbers match)
            winning_number_index = current_index # Current index is written to winning_number_index
            break # Exit "for" without finishing
        else: # Not all numbers match
            current_index += 1 

print(winning_number_index)

这将打印条目中第一个中奖号码的索引(如果您想要所有索引,请在 cmets 中写下它)。

注意:这不是解决问题的最佳代码。如果您不熟悉 Python 的更高级功能,则更容易理解和调试。


您可能应该考虑不要缩写您的变量。 entries_readerreadere 多花一秒钟的时间来写,5 秒的时间来理解。


这是更快、更短、内存效率更高的变体,但可能更难理解:

with open('winningnumbers.csv', 'rb') as wn:
    reader = csv.reader(wn)
    winningnumbers = list(reader)

with open('Entries#x.csv', 'rb') as en:
    readere = csv.reader(en)
    for line_index, line in enumerate(readere):            
        if all((line[i] == winningnumbers[i] for i in xrange(len(line)))):
            winning_number_index = line_index
            break
    else:
        winning_number_index = -1

print(winning_number_index)

我可能不清楚的功能可能是enumerate()any() 和在for 中使用else 而不是在if 中。让我们一一浏览。


要了解枚举的这种用法,您需要了解该语法:

a, b = [1, 2]

变量ab 将根据列表中的值进行分配。在这种情况下,a 将是 1,b 将是 2。使用这种语法,我们可以做到这一点:

for a, b in [[1, 2], [2, 3], ['spam', 'eggs']]:
    # do something with a and b

在每次迭代中,a 和 b 将分别为 1 和 2、2 和 3、'spam' 和 'eggs'。

假设我们有一个列表a = ['spam', 'eggs', 'potatoes']enumerate() 只返回一个像这样的“列表”:[(1, 'spam'), (2, 'eggs'), (3, 'potatoes')]。所以,当我们这样使用它时,

for line_index, line in enumerate(readere):
    # Do something with line_index and line

line_index 将是 1、2、3 等


any() 函数接受一个序列(列表、元组等),如果其中的所有元素都等于True,则返回True

生成器表达式mylist = [line[i] == winningnumbers[i] for i in range(len(line))]返回一个列表,类似如下:

mylist = []
for i in range(len(line)):
    mylist.append(line[i] == winningnumbers[i]) # a == b will return True if a is equal to b

所以any 只有在输入的所有号码都与中奖号码匹配的情况下才会返回 True。


forelse 部分中的代码仅在for 未被break 中断时调用,因此在我们的情况下,最好设置一个默认索引以返回。

【讨论】:

  • 感谢您的回复!我运行了第二个代码并得到了-1的回报。我认为这是因为没有匹配所有 5 个索引?感谢您的提示,我以后不会这样做了。
  • 是的,如果我的代码没有错误的话。我将根据我的建议评论更高级的代码并更改变量名称。
  • 明白了。感谢您添加 cmets 确实有助于理解。让我在所有 5 个数字都匹配的 CSV 文件中添加另一行。
  • @Joshua,您是否正在寻找任何数字或所有数字来匹配,因为它们是两个完全不同的东西?
  • 如果我能创造出能显示所有匹配项的东西,那就太好了。例如 x 匹配 2 个数字,z 匹配 3 等等。所以无论匹配多少,它都会显示为“赢家”。
【解决方案2】:

重复数字似乎不合逻辑,但如果您想获取每行匹配数字的计数而不考虑索引,则将 nums 设为一个集合并将每行数字在集合中的时间相加:

from itertools import islice, imap
import csv
with open("in.txt") as f,open("numbers.txt") as nums:
    # make a set of all winning nums
    nums = set(imap(str.rstrip, nums))
    r = csv.reader(f)
    # iterate over each row and sum how many matches we get
    for row in r:
        print("{} matched {}".format(row[0], sum(n in nums
                                                 for n in islice(row, 1, None))))

使用您的输入将输出:

a matched 0
b matched 1
c matched 2
d matched 1
e matched 0
f matched 2
g matched 0
h matched 1
i matched 1
j matched 2

假设您的文件以逗号分隔,并且您的数字文件中每行都有一个数字。

如果您真的想知道存在哪些数字,那么您需要遍历该数字并打印我们集合中的每个数字:

from itertools import islice, imap
import csv

with open("in.txt") as f, open("numbers.txt") as nums:
    nums = set(imap(str.rstrip, nums))
    r = csv.reader(f)
    for row in r:
        for n in islice(row, 1, None):
            if n in nums:
                print("{} is in row {}".format(n, row[0]))
        print("")

但同样,我不确定重复数字是否有意义。

要根据匹配的数量对行进行分组,您可以使用 dict 使用 sum 作为键并附加第一列值:

from itertools import islice, imap
import csv
from collections import defaultdict
with open("in.txt") as f,open("numbers.txt") as nums:
    # make a set of all winning nums
    nums = set(imap(str.rstrip, nums))
    r = csv.reader(f)
    results = defaultdict(list)
    # iterate over each row and sum how many matches we get
    for row in r:
        results[sum(n in nums for n in islice(row, 1, None))].append(row[0])

结果:

defaultdict(<type 'list'>,
 {0: ['a', 'e', 'g'], 1: ['b', 'd', 'h', 'i'], 
 2: ['c', 'f', 'j']})

键是数字匹配,值是匹配 n 个数字的行 ID。

【讨论】:

  • 运行此代码时,第 2 行出现语法错误。这比我所知道的要高级一些,所以我不确定为什么会出现这种语法错误。
  • 你用的是python2还是3?
  • 我使用的是 Python 2.7,抱歉应该事先提到。
  • 运行第二个代码,第一个只有 python3 语法,你是要匹配任何数字还是所有数字?
  • 如果我想为匹配 1 个数字的任何条目创建某种列表,并分配给一个列表,并且将匹配 2 的条目添加到另一个列表等。什么是最好的方法这样做?
猜你喜欢
  • 2014-08-24
  • 1970-01-01
  • 2015-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多