Поиск элементов в списках ассоциаций python эффективно
У меня есть набор списков, которые выглядят следующим образом:
conditions = [
["condition1", ["sample1", "sample2", "sample3"]],
["condition2", ["sample4", "sample5", "sample6"],
...]
как я могу сделать следующие вещи эффективно и элегантно в Python?
-
Найти все элементы в определенном условии?
например. получить все образцы в условии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? Есть, наверное, умные лайнеры?
Ответы
Ответ 1
Хорошо, если вы вынуждены держать эту неуклюжую структуру данных, вы не можете ожидать многого. Однострочный эквивалент вашего первого решения будет примерно таким:
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]]
Обратите внимание, что ключ к причине, по которой этот последний подход выполняется быстрее, заключается в том, что он использует правильные структуры данных (набор и dict) - к сожалению, он должен сам их создавать, потому что входящий conditions
вложенный список действительно неправильная структура данных.
Не удалось ли инкапсулировать conditions
как переменную-член класса, которая строит критические (правые, быстрые) вспомогательные структуры данных только один раз? Например:.
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
Это больше похоже на работу для 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']
Ответ 3
Вам нужно использовать 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']
Ответ 4
По первому вопросу:
>>> dict(conditions)['condition1']
['sample1', 'sample2', 'sample3']
На # 2 (не совсем понятно, что вы подразумеваете под "упорядоченным союзом", поэтому я делаю предположение "упорядоченные списки, объединенные по порядку" ):
>>> tmpdict = dict(conditions)
>>> sum( map(tmpdict.get, ["condition1", "condition2"]), [] )
['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']
Забастовкa > пс. пример амортизируется по адресу A.M. законная критика - из-за проблем с реализацией sum()
проявляется квадратичное поведение с увеличением размера списка. Вместо этого я предлагаю код ниже:
>>> import operator
>>> tmpdict = dict(conditions)
>>> reduce(operator.iadd, map(tmpdict.get, ["condition1", "condition2"]), [] )
['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']