关于python:通过正则表达式匹配过滤字典列表

Filtering list of dictionaries by regex match

我正在编写一个收集度量的python脚本,我有:

  • collected,包含所有消息的列表,存储为字典。
  • denied_metrics,包含所有已编译正则表达式的列表。

我希望能够阻止那些collected[i]['service']denied_metrics中至少一个正则表达式匹配的消息的转发。

我试图用清单理解和filter来实现我的目标,但我没有做到。

实际解

假定消息具有以下结构:

1
2
3
4
5
msg = {
  'service': 'foo',
  'metric':    1.0,
  'denied':  False
}

实际上,我正在过滤所有collected消息,如下所示

1
2
3
4
5
6
7
def filter_denied( denied_metrics, collected ):
  for pattern in denied_metrics:
    for msg in collected
      if pattern.match( msg['service'] ):
        msg['denied'] = True

return [ msg for msg in collected if msg['denied'] is not True ]

问题

有(更好的)吗?仅仅使用列表理解和filterreduce的组合获得允许的消息列表的方法?

编辑

我不知道是否有可能像他在回答中建议的那样解决这个问题。


IIUC,我可能会做一些像

1
2
3
allowed = [msg for msg in collected
           if not any( dm.search(msg['service'])
                       for dm in denied_metrics) ]

例如:

1
2
3
4
5
6
7
8
9
10
11
12
>>> pprint.pprint(collected)
[{'denied': False, 'metric': 1.0, 'service': 'ab'},
 {'denied': False, 'metric': 1.0, 'service': 'bc'},
 {'denied': False, 'metric': 1.0, 'service': 'ca'},
 {'denied': False, 'metric': 1.0, 'service': 'cb'},
 {'denied': False, 'metric': 1.0, 'service': 'bc'}]
>>> denied_metrics = [re.compile("a"), re.compile("c$")]
>>> allowed = [msg for msg in collected
               if not any(dm.search(msg['service'])
               for dm in denied_metrics)]
>>> allowed
[{'metric': 1.0, 'service': 'cb', 'denied': False}]

当然,你想要search还是match取决于你的正则表达式。[顺便说一句,"拒绝服务"不是更好的名字吗?]


你有一个xy问题。

在迭代列表时,有两种方法可以删除列表中的元素:

1
2
3
4
5
6
7
li = ['a',12,45,'h',56,'ju',0]
print li
for i in xrange(len(li)-1,-1,-1):
    if isinstance(li[i],int):
        del li[i]
print li
# prints ['a', 'h', 'ju']

.

1
2
3
4
5
6
7
li = ['a',12,45,'h',56,'ju',0]
L = len(li)
for i,x in enumerate(reversed(li),1):
    if isinstance(x,str):
        del li[L-i]
print li
# prints [12, 45, 56, 0]

在最后一个代码中,reversed()返回迭代器,不需要创建新的列表。