【问题标题】:Python Nested For Loop with Two Dictionaries, Inner Loop Not ResettingPython嵌套了两个字典的For循环,内循环不重置
【发布时间】:2021-11-07 08:28:46
【问题描述】:

我正在尝试比较两个 csv 文件之间的特定值。我使用 csv.DictReader() 函数读取了两个 csv 文件,并且我有一个嵌套的 for 循环,每个循环都通过一个阅读器。当然,对于外部循环的每次迭代,通常内部 for 循环都会重置并遍历其整个循环,但对我而言并非如此。当使用我的调试器时,我可以在外循环的第二次迭代中看到,代码完全跳过了内循环,就好像没有任何东西可以循环一样。这是由于遍历字典阅读器对象的属性吗?如果是这样,我该如何解决?我在下面包含了我的代码的 sn-p。

with open('csv1.csv', 'r') as inFile1:
   with open('csv2.csv', 'r') as inFile2:
      reader1 = csv.DictReader(inFile1)
      reader2 = csv.DictReader(inFile2)

      for row1 in reader1:
         for row2 in reader2:
            if row1['key1'] == row2['key2']:
               [Perform other operations here]

【问题讨论】:

  • 您确定要将row1['key1']row2['key2'] 进行比较还是要将其与row2['key1'] 进行比较?
  • 那些是迭代器,它们是迭代器应该的单通道。您可以“破解”并将底层文件对象的光标移回开头。或者,您可以从一个或两个阅读器中列出一个列表,然后循环遍历它。如果内存是一个问题,您可以重新打开第二个文件并在外部循环的主体内创建 csv 阅读器对象
  • 这里的内存是个大问题吗?一般来说,您希望将with 块限制为仅读/写操作,并且任何数据操作都应该在读入文件后发生......您也不需要嵌套with 块,您可以打开@987654321 @

标签: python csv dictionary for-loop


【解决方案1】:

一旦你用尽了一个迭代器,它就不会自动重置。

相反,您必须为每个外部迭代提供一个新的内部迭代器。

with open('csv1.csv', 'r') as inFile1:
    reader1 = csv.DictReader(inFile1)

    for row1 in reader1:
        with open('csv2.csv', 'r') as inFile2:
            reader2 = csv.DictReader(inFile2)
            for row2 in reader2:
                if row1['key1'] == row2['key2']:
                    [Perform other operations here]

或者,如果文件大小合理,只需在处理文件之前将文件读入内存即可:

with open('csv1.csv', 'r') as inFile1, open('csv2.csv', 'r') as inFile2:
    csv1 = list(csv.DictReader(inFile1))
    csv2 = list(csv.DictReader(inFile2))
    
for dict1 in csv1:
    for dict2 in csv2:
        if dict1['key1'] == dict2['key2']:
            [Perform other operations here]                        

【讨论】:

    【解决方案2】:

    @djones 的答案有效,但效率极低,因为它需要 O(nxm) 的时间复杂度,其中 nm 是数字两个文件的行数。

    如果你从第一个文件中构建一个以key1 为键的字典,并通过第二个文件迭代行以在字典中找到key2 的匹配项,则可以在线性时间内解决该问题。由于 dict 查找的平均时间复杂度为 O(1),因此整体时间复杂度将变为 O(n)

    with open('csv1.csv', 'r') as inFile1:
        rows1 = {row1['key1']: row1 for row1 in csv.DictReader(inFile1)}
    with open('csv2.csv', 'r') as inFile2:
        for row2 in csv.DictReader(inFile2):
            key = row2['key2']
            if key in rows1:
                print(rows1[key], row2)
    

    如果两个 CSV 文件中的两个表的键是多对多的关系,但是,您可以将第一个文件读入列表的 dict 中,这样您仍然可以从中查找键第二个文件以恒定时间完成整个过程,以O(n + m + k)的线性时间复杂度完成整个过程,其中nm是两个文件的记录数,k是匹配数:

    rows1 = {}
    with open('csv1.csv', 'r') as inFile1:
        for row1 in csv.DictReader(inFile1):
            rows1.setdefault(row1['key1'], []).append(row1)
    with open('csv2.csv', 'r') as inFile2:
        for row2 in csv.DictReader(inFile2):
            for row1 in rows1.get(row2['key2'], ()):
                print(row1, row2)
    

    Demo here

    【讨论】:

    • @don'ttalkjustcode 除非是多对多关系的两个表,否则您只需将csv2.csv 读入dict 而不是您的示例中的csv1.csv,并遍历表持有外键。将展示一个示例,说明如何在线性时间内处理多对多关系。
    • @don'ttalkjustcode 我已经相应地更新了答案。
    • 看起来不错,甚至还有我忘记的()。只是也许添加“线性时间”意味着 O(n + m + #matches)。
    • 听起来不错。在可能的情况下,我更喜欢 () 而不是 [],因为元组比创建列表更便宜、更快。
    猜你喜欢
    • 2020-09-13
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    相关资源
    最近更新 更多