【问题标题】:How to check if an item in a dictionary exists in CSV file?如何检查字典中的项目是否存在于 CSV 文件中?
【发布时间】:2020-03-12 23:55:40
【问题描述】:

我有一本字典和一个 CSV 文件(实际上是制表符分隔的):

dict1

{1 : ['Charles', 22],
2: ['James', 36],
3: ['John', 18]}

data.csv:


[ 22 | Charles goes to the cinema | Activity    ]
[ 46 | John is a butcher          | Profession  ]
[ 95 | Charles is a firefighter   | Profession  ]
[ 67 | James goes to the zoo      | Activity    ]

我想在dict1的值的第一项中获取字符串(名称)并在csv的第二列中搜索它。如果名字出现在句子中,我想打印第一个(并且只有第一个)句子。

但我在搜索时遇到问题 - 如何在迭代 dict1 时访问列/行数据?我尝试过这样的事情:

with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.reader(file, delimiter='\t')
    for (id, (name, age)) in dict1.items():
        if name in reader.row[1] # reader.row[1] is wrong!!!
        print(reader.row[1])

【问题讨论】:

  • 这里不用遍历字典,这就是 O(1) 查找速度的重点
  • 你的 csv 有多大?
  • @roganjosh 如果您想使用字典中的每个键,您可以遍历字典...
  • 方法是倒退的。您希望遍历行并检查条目是否在字典中,而不是迭代字典并查看它是否与每一行匹配
  • 大家好,字典大约有 5,000 行,而 cab 大约有 20,000。

标签: python loops csv


【解决方案1】:

是的,roganjosh 是对的。更好的方法是遍历 CSV 文件并找到任意键。

requested = {d[0] for d in dict1.values()}
with open('/tmp/f.csv', newline='') as csvfile:
    for row in csv.reader(csvfile, delimiter='\t'):
        sentence = row[1]
        found = {n for n in requested if n in sentence}
        for n in found:
            print(f'{n}: {sentence}')
        requested -= found
        if not requested:  # optimization, all names used
            break

编辑:回答问题,而不是我的想象


EDIT2:在澄清(和一些新要求)之后......我希望我成功了。

每行仅打印句子。它不检查同一个句子是否在另一行中。您可以使用set() 保留匹配的句子,并在 CVS 文件处理完毕后打印出来。

我使用正则表达式来匹配世界而不是任何子字符串。

import csv
import re

requested = {re.compile(r'\b' + re.escape(d[0]) + r'\b') for d in dict1.values()}
with open('/tmp/f.csv', newline='') as csvfile:
    for row in csv.reader(csvfile, delimiter='\t'):
        sentence = row[1]
        found = {n for n in requested if n.search(sentence)}
        if found:
            requested -= found
            print(sentence)
        if not requested:
            break

EDIT3:恢复命中名称(新要求——就像在真正的开发项目中一样:-P)

首先,您可以匹配多个名称(请参阅len(found))。

在上一个示例中,您可以从已编译的正则表达式中恢复名称(因为在名称之前和之后添加了 r'\b'):

found_names = [r.pattern[2:-2] for r in found]

但我认为这不是最好的方法。

更好的方法是将原始名称添加到requested。我决定使用settuples。对集合的操作非常快。

requested = {(re.compile(r'\b' + re.escape(d[0]) + r'\b'), d[0])
             for d in dict1.values()}
with open('/tmp/f.csv', newline='') as csvfile:
    for row in csv.reader(csvfile, delimiter='\t'):
        sentence = row[1]
        found = {(r, n) for r, n in requested if r.search(sentence)}
        if found:
            found_names = tuple(n for r, n in found)
            print(found_names, sentence)
            requested -= found
        if not requested:
            break

现在找到的名称(原始d[0])在列表found_names 中。您可以根据需要使用它。例如更改为字符串(替换 found_name= 和 print` 行):

found_names = ', '.join(n for r, n in found)
print(f'{found_names}: {sentence}')

【讨论】:

  • 非常感谢,但恐怕我无法让它工作!对我来说,这只是在csvfile 中打印第一个row[1]/sentence,并且(当我要求它打印d[0] 以进行调试时)d[0] 没有出现在那个row[1] 中。如果我的问题不清楚,我希望为dict1.values() 中的每个d[0] 打印一个row[1],并让row[1] 成为csvfile 中包含该@ 的第一个row[1] 987654347@.
  • 这很奇怪,它对我有用,或者我不明白线索。如果它打印第一行可能是第一行(行 [1] 包含在 dict1 中定义的一个替代项?可以检查一下吗?如果可能的话,最好的办法是查看所有输入数据。哦……对于每个 d[0]不为任何人!抱歉,我现在要更改答案...
  • 是的!尽管在测试时我意识到这是拿起d[0] 字符串,换句话说(例如'Jonathan' 中的'Jon')- 即d[0] 需要被空格包围。当我组装dict1 时,我可以在d[0] 周围添加一个空格,但这很麻烦。有没有办法在迭代时添加空格?
  • 另外我承认这在我最初的问题中并不清楚,因为我当时没有考虑过,但这将导致sentence 被分配和打印不止一次,如果有在那个sentence 中不止一个d[0]。阻止这种情况的最简单方法是什么?我猜不是只做printnsentence 可以存储在字典中,可以在迭代期间检查sentence
  • 是的,我特地为任何作者添加了打印语句。现在我每行打印一次。如果句子可以在另一行重复,请使用set()。正则表达式现在只检测整个单词。
猜你喜欢
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2016-05-20
  • 2014-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多