按多个值过滤字典

时间:2016-04-05 13:30:59

标签: python python-2.7 dictionary

我是Python的新手,我很难制定一种过滤字典的“pythony”方法。

我的字典看起来像这样:

'217': {'586': 2.0, '578': 5.0, '172': 1.0, '1222': 1.0, '597': 4.0, '1303': 2.0, '195': 5.0, ...}
'660': {'176': 4.0, '174': 3.0, '231': 5.0, '233': 4.0, '797': 4.0, '541': 3.0, '27': 1.0, '210': 4.0, ...}

等等。

然后我有一个字符串列表:

['2', '4', '17', '21', '22', '24', '27', '28', '29', '33', '39', ...]

我想要实现的是一个过滤字典,其中只存在字符串列表中包含任何值的元组。我设法做到了这一点,但只使用一个字符串作为要求,它看起来像这样:

filtered_dict = {k: v for (k, v) in my_dict.iteritems() if my_list[0] in v}

但是,如果我删除[0],我会收到以下错误:

TypeError:不可用类型:'list' 以下是一些预期的输出值:

'115 : {'174': 4.0, '172': 4.0, '27': 3.0, '183': 5.0, '180': 3.0, '1039': 5.0, ... }

'212' : {'4': 3.0, '473': 4.0, '208': 5.0, '123': 4.0, '476': 3.0, '474': 4.0, ...}

正如您所看到的,第一个元组中的第三个值在其中为“27”,位于my_list中。 第二个元组中的第一个值的值为'4',也在my_list中。

我非常感谢对此有任何帮助。

谢谢!

2 个答案:

答案 0 :(得分:4)

你可以使用一个集合,如果值与集合不相交,则保持对:

st = {'2', '4', '17', '21', '22', '24', '27', '28', '29', '33', '39'}

filtered_dict = {k: v for (k, v) in my_dict.iteritems() if not st.isdisjoint(v)}

如果他们不共享至少一个元素,他们将只是脱节:

In [6]: st ={1,2,3}

In [7]: v = [1,4,5]

In [8]: st.isdisjoint(v)
Out[8]: False

In [11]: v = [7,4,5]

In [12]: st.isdisjoint(v)
Out[12]: True

有点相当于:

st = {'2', '4', '17', '21', '22', '24', '27', '28', '29', '33', '39'}

filtered_dict = {k: v for (k, v) in my_dict.iteritems() if any(val in st for val in v)}

如果来自v的any元素在集合中,我们保留元素。

最糟糕的情况是,我们针对集合检查len(v)元素,迭代mylist元素并检查x是否在v中O(len(my_list))对于每种情况,并且还创建相同的k,v每当你得到一场比赛时配对。

如果我们添加一个包含更多匹配键的dict并将这些对添加到列表中,您可以看到会发生什么:

In [22]: my_list  = ['2', '4', '17', '21', '22', '24', '27', '28', '29', '33', '39']

In [23]: my_dict = {'217': {'586': 2.0, '578': 5.0, '172': 1.0, '1222': 1.0, '597': 4.0, '1303': 2.0, '195': 5.0},
   ....:            '660': {'176': 4.0, '174': 3.0, '231': 5.0, '233': 4.0, '797': 4.0, '541': 3.0, '27': 1.0, '210': 4.0},
   ....:            '661': {'2': 4.0, '4': 3.0, '29': 5.0, '17': 4.0, '39': 4.0, '541': 3.0, '27': 1.0, '210': 4.0}}


In [24]: print [(k,v) for k,v in my_dict.iteritems() for x in my_list if x in v]
[('661', {'541': 3.0, '39': 4.0, '2': 4.0, '4': 3.0, '17': 4.0, '210': 4.0, '27': 1.0, '29': 5.0}), ('661', {'541': 3.0, '39': 4.0, '2': 4.0, '4': 3.0, '17': 4.0, '210': 4.0, '27': 1.0, '29': 5.0}), ('661', {'541': 3.0, '39': 4.0, '2': 4.0, '4': 3.0, '17': 4.0, '210': 4.0, '27': 1.0, '29': 5.0}), ('661', {'541': 3.0, '39': 4.0, '2': 4.0, '4': 3.0, '17': 4.0, '210': 4.0, '27': 1.0, '29': 5.0}), ('661', {'541': 3.0, '39': 4.0, '2': 4.0, '4': 3.0, '17': 4.0, '210': 4.0, '27': 1.0, '29': 5.0}), ('661', {'541': 3.0, '39': 4.0, '2': 4.0, '4': 3.0, '17': 4.0, '210': 4.0, '27': 1.0, '29': 5.0}), ('660', {'797': 4.0, '27': 1.0, '541': 3.0, '210': 4.0, '176': 4.0, '174': 3.0, '231': 5.0, '233': 4.0})]

因为有7个匹配,我们七次得到相同的配对,你不会在dict中得到dupes,但你必须迭代len(my_list)次并创建x in v的配对长度为True倍。随着my_list的长度增加,运行时间将相应增加。

只是将my_list 1000元素放在一起有很大的不同:

In [35]: len(my_list)
Out[35]: 1000

In [36]: %%timeit
   ....: st = set(my_list)
   ....: {k: v for (k, v) in my_dict.iteritems() if not st.isdisjoint(v)}
   ....: 
10000 loops, best of 3: 21.9 µs per loop
In [37]: timeit {k:v for k,v in my_dict.iteritems() for x in my_list if x in v}
10000 loops, best of 3: 136 µs per loop

几乎所有的时间花费在集合创建中,如果你从一开始就使用一套它运行速度快100倍:

In [40]: timeit {k: v for (k, v) in my_dict.iteritems() if not st.isdisjoint(v)}

1000000 loops, best of 3: 1.09 µs per loop

答案 1 :(得分:3)

如果我理解你的问题,你需要遍历列表mylist并将每个元素与字典mydict的值进行比较

{k:v for k,v in mydict.iteritems() for x in mylist if x in v}

1)k:v for k,v in mydict.iteritems()按对方迭代字典对。

2)对于x in mylist如果x中的x是迭代mylist并检查mylist元素in是否内部字典v,因此检查x in v等于检查x in v.keys()中的哪个x v的键