【问题标题】:Python dict key delete if pattern match with other dict key如果模式与其他字典键匹配,则 Python 字典键删除
【发布时间】:2012-10-18 20:29:04
【问题描述】:

Python dict 键删除,如果键模式与其他 dict 键匹配。

例如

a={'a.b.c.test':1,  'b.x.d.pqr':2,  'c.e.f.dummy':3,  'd.x.y.temp':4}

b={'a.b.c':1,  'b.p.q':20}

结果

a={'b.x.d.pqr':2,'c.e.f.dummy':3,'d.x.y.temp':4}`  

【问题讨论】:

  • 你能详细说明“模式匹配”吗?更笼统地说,您的问题到底是什么?
  • 我喜欢从 dict a 中删除键,与 dict b 进行比较。但是,dict a 和 dict b 的键不相同,所以比较是行不通的。因此,我需要将 dict b 的键中的模式与 dict a 匹配,如果键模式匹配,则只删除 dict a 中的键。结果,我将在上面的示例中显示 dict a。
  • 你还没有解释你所说的“匹配模式”、“关键模式匹配”等是什么意思。我们知道与==比较是不够的,但你需要什么代替吗?

标签: python design-patterns dictionary key


【解决方案1】:

如果“pattern match with other dict key”的意思是“从另一个dict中的任何键开始”,最直接的写法是这样的:

a = {k:v for (k, v) in a.items() if any(k.startswith(k2) for k2 in b)}

如果乍一看很难理解,基本上就是这样的:

def matches(key1, d2):
    for key2 in d2:
        if key1.startswith(key2):
            return True
    return False

c = {}
for key in a:
  if not matches(key, b):
    c[key] = a[key]
a = c

这将比必要的慢。如果a 有 N 个键,b 有 M 个键,则所用时间为 O(NM)。虽然您可以在恒定时间内检查“在 dict b 中是否存在键 k”,但如果不遍历整个字典,则无法检查“在 dict b 中是否存在任何以 k 开头的键”。因此,如果b 可能很大,您可能想要搜索sorted(b.keys()) 并编写二进制搜索,这将使时间减少到 O(N log M)。但如果这不是瓶颈,您最好还是坚持使用简单版本,因为它很简单。

请注意,我正在生成一个新的a 过滤掉匹配项,而不是删除匹配项。由于多种原因,这几乎总是比就地删除更好的解决方案: *它更容易推理。将对象视为不可变对象并对它们执行纯操作意味着您无需考虑状态如何随时间变化。例如,在原地删除的天真方法会遇到您在迭代字典时更改字典的问题,这将引发异常。如果没有可变操作,这样的问题永远不会出现。 * 它更容易阅读,并且(一旦你掌握了它)甚至写作。 * 它几乎总是更快。 (一个原因是重复修改字典需要更多的内存分配和解除分配,而不是构建一个具有理解的字典。)

一个权衡是内存使用。就地删除实现必须复制所有键; built-a-new-dict 实现必须在内存中同时包含过滤后的 dict 和原始 dict。如果您保留 99% 的值,并且值比键大得多,这可能会伤害您。 (另一方面,如果您保留 10% 的值,并且这些值与键的大小大致相同,那么您实际上会节省 空间。)这就是为什么它“几乎总是" 一个更好的解决方案,而不是"总是"。

【讨论】:

    【解决方案2】:
    for key in list(a.keys()):
        if any(key.startswith(k) for k in b):
           del a[key]
    

    key.startswith(k) 替换为“匹配”的适当条件。

    【讨论】:

    • 在迭代字典时不能从字典中删除。您可以遍历一个副本,例如list(a.keys()),然后从a 中删除,但这通常是个坏主意。过滤dict 几乎总是更好的方法是生成一个新的dict,只包含你想要的值。它可能会也可能不会使用更多空间(您需要通过过滤器的所有键和值的副本,而不是所有键的副本),但它更快、更简单、更容易推理。
    • 是的,对不起,我的错。 @abarnert 是 100% 正确的。固定的,有点。我选择删除是因为这是 OP 要求的,尽管也许创建一个新的 dict 也可以。
    • 我仍然会添加一条评论,说明删除很可能不是 OP 真正想要的,即使它是可能的。许多人这样做是因为他们认为这样做会更有效或更简单,但他们在这两方面都错了。
    • @abarnert 我个人认为您的评论已经足够了,但是您可以通过任何方式编辑我的帖子 :) 或者在您的答案中解释所有内容,我已经认为这是最彻底的。
    【解决方案3】:
    c={} #result in dict c
    for key in b.keys():
        if all([z.count(key)==0 for z in a.keys()]): #string of the key in b should not be substring for any of the keys in a
           c[key]=b[key]
    

    【讨论】:

      猜你喜欢
      • 2019-10-26
      • 2018-12-24
      • 2014-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      相关资源
      最近更新 更多