从列表中选择性打印

3 投票
4 回答
789 浏览
提问于 2025-04-16 18:08

举个例子,我有这样一个列表:

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 个回答

1

对于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
2

首先,我建议你把数据存储在 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"
1

最常见的方法是使用列表推导式,比如说可以根据用户名来筛选:

[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)

撰写回答