从列表中选择性打印
举个例子,我有这样一个列表:
q_list = [('94.vmtest2', 'sgmops', 'Andy Hays', '27/04 00:27:26', 'C', '27/04 00:28:31', 'vmtest1.hep', 'express', '00:00:10', '00:01:04'),
('96.vmtest2', 'sgmops', 'John Dee', '27/04 01:27:26', 'C', '27/04 01:28:33', 'vmtest1.hep', 'short', '00:00:09', '00:01:06'),
('99.vmtest2', 'sgmops', 'Andy Hays', '27/04 07:19:56', 'C', '27/04 07:21:12', 'vmtest1.hep', 'express', '00:00:10', '00:01:14'),
('103.vmtest2', 'sgmops', 'John Dee', '27/04 14:08:00', 'C', '27/04 14:09:16', 'vmtest1.hep', 'express', '00:00:10', '00:01:16'),
('102.vmtest2', 'sgmops', 'John Dee', '27/04 14:02:38', 'C', '27/04 14:10:12', 'vmtest1.hep', 'short', '00:00:10', '00:01:10')]
这个列表是从日志文件中生成的。然后我还有一个字典,长这样:
q_dict = {'username': 'johndee', 'queue': 'short'}
这个字典是根据用户输入的查询字符串生成的。我想做的是打印出列表中与字典里的值匹配的前8行内容。在这个例子中,我只会打印出这两行:
96.vmtest2 sgmops John Dee 27/04 01:27:26 C 27/04 01:28:33 vmtest1.hep short
102.vmtest2 sgmops John Dee 27/04 14:02:38 C 27/04 14:10:12 vmtest1.hep short
其实,这个东西不一定非得是字典;用户输入(命令行参数)是这样的:
'formatDate(%m/%d) == 4/27 && username == John Dee && queue == short'
我就是根据这个输入来创建字典的。有没有人知道我该怎么做呢?提前谢谢大家的帮助!祝好!!
4 个回答
对于formatDate这个东西,可能会比较复杂,但如果只是简单的比较相等,可以用eval来实现:
test_string = "username == 'John Dee' && queue == 'short'"
for a, b, username, formatDate, d, e, f, queue, g, h in q_list:
if eval(test_string.replace('&&', 'and')):
print '%s: %s' % (username, queue)
你可以通过把' || '替换成'or'来创建“或”语句,这样做比较灵活
别忘了把值放在引号里(不是queue == short
,而是queue == 'short'
)
在给定的q_list上,结果是:
John Dee: short
John Dee: short
首先,我建议你把数据存储在 namedtuple
或者自定义类里,而不是直接用普通的元组。这样你就可以通过名字来访问属性,比如用 operator.attrgetter
。另外一个选择是使用 dict
(字典)。
然后,你可以简单地这样做(假设你的项目是 dict
):
[item for item in q_list if all((item[attr] == q_dict[attr])
for q_dict in filters)]
当然,这样做只有在你的条件总是遵循你问题中展示的模式时才有效(没有 ||
,没有 !=
之类的东西)。
如果你只能使用元组,那你可以创建一个字典,把属性的名字映射到元组的索引。
现在,当你打印它们的时候,你只需要创建一个要打印的属性列表,然后这样使用:
for item in filtered_items:
print "\t".join(item[attr] for attr in attributes_to_print) + "\n"
最常见的方法是使用列表推导式,比如说可以根据用户名来筛选:
[x for x in q_list if x[2] == 'John Dee']
你也可以使用filter
函数:
filter(lambda x: x[2] == 'John Dee', q_list)
这样你就可以轻松地用你的q_dict
来根据用户和/或队列进行筛选。
[x for x in q_list if [x[2].lower().replace(' ', ''), x[7]] == q_dict.values()]
正如Space_C0wb0y的回答所建议的,使用namedtuple
会是一个不错的选择,这样你可以比较容易地映射出字段:
fields = ['field1', 'field2', 'username', 'field4', 'field5', 'field6', 'field7', 'queue', 'field9', 'field10']
Item = namedtuple('Item', fields)
为了说明这个问题,我们可以把你列表中的元组转换成命名元组:
q_namedtuple = [Item(*x) for x in q_list]
然后你可以根据查询参数动态地进行筛选。例如,获取一个所有查询参数都匹配给定字段的项目列表:
[item for item in q_namedtuple if all(getattr(item, k) == v for k, v in q_dict.iteritems())]
这假设q_dict
中的用户名确实和用户名字段匹配……在你的例子中并没有,但你可以找到解决办法。同样,你也可以创建一个字典列表,这样处理你的列表会简单一些:
q_list_of_dicts = [dict(zip(fields, x)) for x in q_list]
这将给你一个像这样的字典列表:
{'field1': '102.vmtest2',
...etc
'queue': 'short',
'username': 'John Dee'}
然后你可以用类似的方法进行筛选:
[item for item in q_list_of_dicts if all(item.get(k) == v for k, v in q_dict.iteritems())]
就我个人而言,我更喜欢字典的方法。整个过程可以用for循环来实现(还有一个生成器表达式):
results = []
for item in q_list:
d = dict(zip(fields, item))
# use some other logic to filter
if all(d.get(k) == v for k, v in q_dict.iteritems()):
results.append(d)