【问题标题】:How do I compare multiple key values from a list of dictionaries?如何比较字典列表中的多个键值?
【发布时间】:2014-08-05 21:40:55
【问题描述】:

我有一个字典列表,它们在列表中都具有相同的结构。例如:

test_data = [{'id':1, 'value':'one'}, {'id':2, 'value':'two'}, {'id':3, 'value':'three'}]

我需要做的是比较这些字典中的每一个并根据值键对返回“相似”字典。例如,给定键 value 和值 oen,我想找到与 oen 几乎相似的所有匹配字典,在本例中为 [{'id':1, 'value':'one'}]

difflib 有一个函数 get_close_matches 接近我需要的。我可以使用a list comprehension 提取特定键的值,然后将这些值与我的搜索进行比较:

values = [ item['value'] for item in test_data ]
found_vals = get_close_matches('oen', values) #returns ['one']

我需要做的是更进一步,将所有内容与原始字典联系起来:

In  [1]: get_close_dicts('oen', test_data, 'value')
Out [1]: [{'id':1, 'value':'one'}]

注意:词典列表非常大,因此我希望尽可能高效/快速。

【问题讨论】:

  • 字典列表是不变的,还是会经常变化?
  • 常数。但与该列表进行多次比较。
  • 好的,很高兴知道。在这种情况下,预处理可能是要走的路。我正在寻找答案。

标签: python dictionary compare


【解决方案1】:

您可以在对数据运行 get_close_dicts 之前创建一个反向查找字典,以便在返回一组值后,您可以使用它们来查找相关的字典。

如果您保证在 'value' 键的 dicts 中具有唯一值,那么您可以这样做:

reverselookup = {thedict['value']:thedict for thedict in test_data}

但是,如果您需要处理多个 dict 的“value”键具有相同值的情况,那么您需要映射所有这些(这将为您提供一个 dict,其中键是'value' 并且值是具有该值的字典列表):

from collections import defaultdict
reverselookup = defaultdict(list)
for testdict in test_data:
    reverselookup[testdict['value']].append(testdict)

例如,如果您的测试数据中有一个额外的字典,如下所示:

>>> test_data = [{'id':1, 'value':'one'}, {'id':2, 'value':'two'}, 
                 {'id':3, 'value':'three'}, {'id':4, 'value':'three'}]

那么上面的反向查找结构会给你这个:

{
  "three": [
    {
      "id": 3,
      "value": "three"
    },
    {
      "id": 4,
      "value": "three"
    }
  ],
  "two": [
    {
      "id": 2,
      "value": "two"
    }
  ],
  "one": [
    {
      "id": 1,
      "value": "one"
    }
  ]
}

然后,在您获得值之后,只需检索 dicts(如果您有列表用例列表,则可以链接,如果您有第一个用例,则无需链接):

from itertools import chain    
chain(*[reverselookup[val] for val in found_vals])

【讨论】:

  • 如果您有多个具有相同值的 dict 将覆盖查找。它应该被修复,否则它不会工作
  • 这能满足他的近距离匹配要求吗?
  • 实际上你的原始编辑更接近我想要的。
  • @KronoS 原版不会返回所有字典。如果您不需要所有 dicts,只需要 一个 匹配,那么有一个更好的解决方案..
  • 如果您的所有 test_data dicts 的 'value' 键具有不同的值,它就会起作用。是这样吗?
【解决方案2】:

你可以:

return [d for d in test_data if get_close_matches('oen', [d['value'])]]

注意 get_close_matches 可能返回多个结果。

【讨论】:

  • 如果我没看错,这将遍历列表并比较每个字典。这将在处理时间上非常昂贵:/
  • 你没有在你的问题中提到这是一个问题:) 我会给你一个更有效的
【解决方案3】:

无论如何,您最终都会在某个时候遍历每个字典。没有办法解决这个问题。您可以做的是在预处理阶段完成所有工作,以便立即对函数进行实际调用。

正如 ValAyal 所说,反向查找字典在这里是个好主意。我在想象一个字典value_dict,其中key 是第一个字典中的值,value 包含精确和相似的value 匹配项。以d1d2 为例,它们在您要搜索的列表中。如果

d1 = {'id':1, 'value':'one'}
d2 = {'id':3, 'value':'oen'}

然后:

value_dict["one"] = {"exact": [d1], "close": [d2]}
value_dict["oen"] = {"exact": [d2], "close": [d1]}

每当您插入具有已见过值的字典时,您都可以立即确定所有精确匹配和紧密匹配(只需查找该值),并相应地添加到各种列表中。如果您有一个以前从未见过的新值,则必须将其与 value_dict 中当前的所有值进行比较。例如,如果你想添加

d3 = {'id':5, 'value':'one'}

您将查找 value_dict["one"] 并获得 exactclose 列表。这些列表包括您需要修改的所有其他 value_dict 条目。您需要添加到one 的完全匹配和oen 的紧密匹配;您可以从返回的列表中获得这两个值。你最终得到了

value_dict["one"] = {"exact": [d1, d3], "close": [d2]}
value_dict["oen"] = {"exact": [d2], "close": [d1, d3]}

因此,一旦完成所有预处理,您的函数就会变得更简单:get_close_dicts(val) 之类的东西(我不知道您的示例中的第三个参数做了什么)可以只做 return value_dict[val]["exact"] + value_dict[val]["close"]。您现在有了一个可以立即给出答案的函数。

预处理步骤相当复杂,但 get_close_dicts 中的加速提升有望弥补它。如果您想知道如何实现这一点,我可以在我下班后详细说明这一点。希望这可以让您对有用的数据结构有一个很好的了解,而且我并没有过度考虑这一点。

【讨论】:

    猜你喜欢
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    相关资源
    最近更新 更多