我有一组看起来像这样的列表:
conditions = [
["condition1", ["sample1", "sample2", "sample3"]],
["condition2", ["sample4", "sample5", "sample6"],
...]
如何在Python中高效优雅地完成以下事项?
查找特定条件下的所有元素?
e.g。获取条件2中的所有样本。现在我可以做:
for cond in conditions:
cond_name, samples = cond
if cond_name == requested_cond:
return samples
但那很笨重。
查找条件列表的有序联合?例如。 ordered_union(["condition1", "condition2"], conditions)
应该返回:
["sample1", "sample2", "sample3", "sample4", "sample5", "sample6"]
如何在Python中有效地完成此操作?可能有一个聪明的单线?
答案 0 :(得分:6)
这看起来更像是dict
的作业:
conditions = {
"condition1": ["sample1", "sample2", "sample3"],
"condition2": ["sample4", "sample5", "sample6"],
...}
然后你可以使用
获得“有序联盟”>>> conditions["condition1"]+conditions["condition2"]
['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']
在Python 3.1或2.7中,您可以使用OrderedDict
来保留订单:
from collections import OrderedDict
conditions = OrderedDict([
["condition1", ["sample1", "sample2", "sample3"]],
["condition2", ["sample4", "sample5", "sample6"]]
])
然后你可以得到“有序联盟”,也适用于任意大小的OrderedDicts
:
>>> import itertools
>>> [item for item in itertools.chain(*conditions.values())]
['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']
答案 1 :(得分:4)
好吧,如果你被迫保持那个笨重的数据结构,你不能指望太多。你的第一个解决方案的单行代码将类似于:
def samplesof(requested_cond, conditions):
return next(s for c, s in conditions if c==requested_cond)
而对于第二个,如果你坚持使用单行,那将会是这样的:
def ordered_union(the_conds, conditions):
return [s for c in the_conds for s in samplesof(c, conditions)]
有更快的方法来解决第二个问题,但它们都是多线的,例如:
aux_set = set(the_conds)
samples_by_cond = dict((c, s) for c, s in conditions if c in aux_set)
return [s for c in the_conds for s in samples_by_cond[c]]
请注意,后一种方法更快的关键在于它使用了正确的数据结构(一个集合和一个字典) - 遗憾的是它必须自己构建它们,因为传入的conditions
嵌套列表确实是错误的数据结构。
难道不能将conditions
封装为只构建一次关键(右,快)辅助数据结构的类的成员变量吗? E.g:
class Sensible(object):
def __init__(self, conditions):
self.seq = []
self.dic = {}
for c, s in conditions:
self.seq.append(c)
self.dic[c] = s
def samplesof(self, requested_condition):
return self.dic[requested_condition]
def ordered_union(self, the_conds):
return [s for c in the_conds for s in self.dic[c]]
现在 快速而优雅!
我假设你需要self.seq
(条件序列)用于别的东西(你提到的两个操作当然不需要它!),并且在那个序列中没有重复样本(无论你的实际规格是什么,它们都不会难以适应,但是当你提及它们时,盲目地试图猜测它们将非常坚硬而毫无意义; - )。
答案 2 :(得分:2)
您需要使用dict
(字典)而不是list
。此外,如果您想要有效的基于集合的操作,则可以将样本保留在set
。
conditions = { "condition1" : set(["sample1", "sample2", "sample3"]),
"condition2" : set(["sample4", "sample5", "sample6"]) }
print conditions["condition2"]
# set(['sample5', 'sample4', 'sample6'])
union = conditions["condition1"].union(conditions["condition2"])
print sorted(union)
# ['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']
答案 3 :(得分:2)
关于第一个问题:
>>> dict(conditions)['condition1']
['sample1', 'sample2', 'sample3']
在#2上(你所说的'有序联盟'的含义并不十分清楚,所以我假设'有序列表按顺序连接'): <击> 撞击>
<击>>>> tmpdict = dict(conditions)
>>> sum( map(tmpdict.get, ["condition1", "condition2"]), [] )
['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']
击> <击> 撞击>
PS。示例折旧以解决A.M.的合理批评 - 由于实施问题,sum()
表现出随着列表大小增加的二次行为。相反,我建议使用以下代码:
>>> import operator
>>> tmpdict = dict(conditions)
>>> reduce(operator.iadd, map(tmpdict.get, ["condition1", "condition2"]), [] )
['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']