在python关联列表中有效地查找元素

时间:2010-06-14 19:40:20

标签: python list list-comprehension

我有一组看起来像这样的列表:

conditions = [
["condition1", ["sample1", "sample2", "sample3"]],
["condition2", ["sample4", "sample5", "sample6"],
...]

如何在Python中高效优雅地完成以下事项?

  1. 查找特定条件下的所有元素?

    e.g。获取条件2中的所有样本。现在我可以做:

    for cond in conditions:
      cond_name, samples = cond
      if cond_name == requested_cond:
        return samples
    

    但那很笨重。

  2. 查找条件列表的有序联合?例如。 ordered_union(["condition1", "condition2"], conditions)应该返回:

    ["sample1", "sample2", "sample3", "sample4", "sample5", "sample6"]
    
  3. 如何在Python中有效地完成此操作?可能有一个聪明的单线?

4 个答案:

答案 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']