简体   繁体   English

如何按值过滤字典?

[英]How to filter a dictionary by value?

Newbie question here, so please bear with me. 这里有新手问题,所以请耐心等待。

Let's say I have a dictionary looking like this: 假设我的字典看起来像这样:

a = {"2323232838": ("first/dir", "hello.txt"),
     "2323221383": ("second/dir", "foo.txt"),
     "3434221": ("first/dir", "hello.txt"),
     "32232334": ("first/dir", "hello.txt"),
     "324234324": ("third/dir", "dog.txt")}

I want all values that are equal to each other to be moved into another dictionary. 我希望将所有彼此相等的值移动到另一个字典中。

matched = {"2323232838": ("first/dir", "hello.txt"),
           "3434221":    ("first/dir", "hello.txt"),
           "32232334":   ("first/dir", "hello.txt")}

And the remaining unmatched items should be looking like this: 其余不匹配的项目应如下所示:

remainder = {"2323221383": ("second/dir", "foo.txt"),
             "324234324":  ("third/dir", "dog.txt")}

Thanks in advance, and if you provide an example, please comment it as much as possible. 在此先感谢,如果您提供示例,请尽可能评论。

The code below will result in two variables, matches and remainders . 下面的代码将产生两个变量, matchesremainders matches is an array of dictionaries, in which matching items from the original dictionary will have a corresponding element. matches是一个字典数组,其中原始字典中的匹配项将具有相应的元素。 remainder will contain, as in your example, a dictionary containing all the unmatched items. 在您的示例中, remainder将包含包含所有不匹配项的字典。

Note that in your example, there is only one set of matching values: ('first/dir', 'hello.txt') . 请注意,在您的示例中,只有一组匹配值:( ('first/dir', 'hello.txt') If there were more than one set, each would have a corresponding entry in matches . 如果有一组以上的,每次将安排在对应的条目matches

import itertools

# Original dict
a = {"2323232838": ("first/dir", "hello.txt"),
     "2323221383": ("second/dir", "foo.txt"),
     "3434221": ("first/dir", "hello.txt"),
     "32232334": ("first/dir", "hello.txt"),
     "324234324": ("third/dir", "dog.txt")}

# Convert dict to sorted list of items
a = sorted(a.items(), key=lambda x:x[1])

# Group by value of tuple
groups = itertools.groupby(a, key=lambda x:x[1])

# Pull out matching groups of items, and combine items   
# with no matches back into a single dictionary
remainder = []
matched   = []

for key, group in groups:
   group = list(group)
   if len(group) == 1:
      remainder.append( group[0] )
   else:
      matched.append( dict(group) )
else:
   remainder = dict(remainder)

Output: 输出:

>>> matched
[
  {
    '3434221':    ('first/dir', 'hello.txt'), 
    '2323232838': ('first/dir', 'hello.txt'), 
    '32232334':   ('first/dir', 'hello.txt')
  }
]

>>> remainder
{
  '2323221383': ('second/dir', 'foo.txt'), 
  '324234324':  ('third/dir', 'dog.txt')
}

As a newbie, you're probably being introduced to a few unfamiliar concepts in the code above. 作为一个新手,你可能会在上面的代码中介绍一些不熟悉的概念。 Here are some links: 以下是一些链接:

What you're asking for is called an "Inverted Index" -- the distinct items are recorded just once with a list of keys. 您要求的是“倒置索引” - 不同的项目仅使用一系列键记录一次。

>>> from collections import defaultdict
>>> a = {"2323232838": ("first/dir", "hello.txt"),
...      "2323221383": ("second/dir", "foo.txt"),
...      "3434221": ("first/dir", "hello.txt"),
...      "32232334": ("first/dir", "hello.txt"),
...      "324234324": ("third/dir", "dog.txt")}
>>> invert = defaultdict( list )
>>> for key, value in a.items():
...     invert[value].append( key )
... 
>>> invert
defaultdict(<type 'list'>, {('first/dir', 'hello.txt'): ['3434221', '2323232838', '32232334'], ('second/dir', 'foo.txt'): ['2323221383'], ('third/dir', 'dog.txt'): ['324234324']})

The inverted dictionary has the original values associated with a list of 1 or more keys. 反转字典具有与1个或更多个键的列表相关联的原始值。

Now, to get your revised dictionaries from this. 现在,从中获取修改后的词典。

Filtering: 过滤:

>>> [ invert[multi] for multi in invert if len(invert[multi]) > 1 ]
[['3434221', '2323232838', '32232334']]
>>> [ invert[uni] for uni in invert if len(invert[uni]) == 1 ]
[['2323221383'], ['324234324']]

Expanding 扩大

>>> [ (i,multi) for multi in invert if len(invert[multi]) > 1 for i in invert[multi] ]
[('3434221', ('first/dir', 'hello.txt')), ('2323232838', ('first/dir', 'hello.txt')), ('32232334', ('first/dir', 'hello.txt'))]
>>> dict( (i,multi) for multi in invert if len(invert[multi]) > 1 for i in invert[multi] )
{'3434221': ('first/dir', 'hello.txt'), '2323232838': ('first/dir', 'hello.txt'), '32232334': ('first/dir', 'hello.txt')}

A similar (but simpler) treatment works for the items which occur once. 类似(但更简单)的处理适用于出现一次的物品。

Iterating over a dictionary is no different from iterating over a list in python: 迭代字典与迭代python中的列表没什么不同:

for key in dic:
    print("dic[%s] = %s" % (key, dic[key]))

This will print all of the keys and values of your dictionary. 这将打印字典的所有键和值。

I assume that your unique id will be the key. 我认为你的唯一身份证是关键。
Probably not very beautiful, but returns a dict with your unique values: 可能不是很漂亮,但会返回一个带有您独特价值的字典:

>>> dict_ = {'1': ['first/dir', 'hello.txt'],
'3': ['first/dir', 'foo.txt'], 
'2': ['second/dir', 'foo.txt'], 
'4': ['second/dir', 'foo.txt']}  
>>> dict((v[0]+v[1],k) for k,v in dict_.iteritems())  
{'second/dir/foo.txt': '4', 'first/dir/hello.txt': '1', 'first/dir/foo.txt': '3'}  

I've seen you updated your post: 我见过你更新了你的帖子:

>>> a
{'324234324': ('third/dir', 'dog.txt'), 
'2323221383': ('second/dir', 'foo.txt'), 
'3434221': ('first/dir', 'hello.txt'), 
'2323232838': ('first/dir', 'hello.txt'), 
'32232334': ('first/dir', 'hello.txt')}
>>> dict((v[0]+"/"+v[1],k) for k,v in a.iteritems())
{'second/dir/foo.txt': '2323221383', 
'first/dir/hello.txt': '32232334', 
'third/dir/dog.txt': '324234324'}

if you know what value you want to filter out: 如果您知道要过滤掉的值:

known_tuple = 'first/dir','hello.txt'
b = {k:v for k, v in a.items() if v == known_tuple}

then a would become: 然后a会变成:

a = dict(a.items() - b.items())

this is py3k notation, but I'm sure something similar can be implemented in legacy versions. 这是py3k表示法,但我确信在旧版本中可以实现类似的东西。 If you don't know what the known_tuple is, then you'd need to first find it out. 如果您不知道known_tuple是什么,那么您需要先找到它。 for example like this: 例如像这样:

c = list(a.values())
for i in set(c):
    c.remove(i)
known_tuple = c[0]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM