LIst Comprehension: ссылки на компоненты

В итоге: мне нужно написать понимание списка, в котором я ссылаюсь на список, созданный пониманием списка.

Это может быть не то, что вам нужно делать каждый день, но я не думаю, что это что-то необычное.

Возможно, здесь нет ответа, но, пожалуйста, не говорите мне, что я должен использовать цикл for. Это может быть правильно, но это не полезно. Причина в проблемной области: эта строка кода является частью модуля ETL, поэтому важна производительность, а также необходимость избегать создания временного контейнера, поэтому я хочу закодировать этот шаг в аккредитиве. Если бы для меня здесь работал цикл for, я бы просто закодировал его.

В любом случае, я не могу написать это конкретное понимание списка. Причина: выражение, которое мне нужно написать, имеет следующую форму:

[ some_function(s) for s in raw_data if s not in this_list ]

В этом псевдокоде «this_list» относится к списку, созданному путем оценки понимания этого списка. И вот почему я застрял - потому что this_list не будет создан, пока не будет оценено понимание моего списка, и поскольку этот список еще не создан к тому времени, когда мне нужно сослаться на него, я не знаю, как ссылаться на Это.

То, что я рассмотрел до сих пор (и что может быть основано на одном или нескольких ложных предположениях, хотя я точно не знаю, где именно):

  • разве интерпретатор Python не должен давать этому строящемуся списку имя? я так думаю

  • это временное имя, вероятно, взято из какого-то связанного метода, используемого для создания моего списка («сумма»?)

  • но даже если я приложил усилия, чтобы найти этот связанный метод и предположить, что это действительно временное имя, используемое интерпретатором python для ссылки на список, пока он находится в стадии создания, я почти уверен, что вы не можете ссылаться на связанные методы напрямую; я не знаю о таком явном правиле, но эти методы (по крайней мере, те немногие, на которые я действительно смотрел) не являются допустимым синтаксисом python. Я предполагаю, что одна из причин этого заключается в том, что мы не записываем их в наш код.

такова цепочка моих так называемых рассуждений, которая привела меня к заключению или, по крайней мере, к предположению, что я загнал себя в угол. Тем не менее, я подумал, что должен проверить это с сообществом, прежде чем разворачиваться и идти в другом направлении.


person doug    schedule 20.02.2011    source источник
comment
Похоже, вы хотите set (судя по псевдокоду, остальное я не читал).   -  person kennytm    schedule 20.02.2011
comment
моя вина - я должен был переместить третье с последнего предложения ближе к началу вопроса. Он говорит Но прежде чем кто-нибудь скажет мне, что есть тысяча более простых способов сделать это в питоне - да, я знаю. Это просто пример для иллюстрации проблемы. В моем случае фактическое выражение представляет собой алгоритм выборки   -  person doug    schedule 20.02.2011
comment
(1) Каков результат some_function(s)? s после того, как с ним повозились? (2) s is not in this_list -- каждый s поступает из raw_data; как это могло быть уже в this_list???   -  person John Machin    schedule 20.02.2011
comment
@doug: the actual expression is a sampling algorithm хочешь подробнее рассказать об этом?   -  person eat    schedule 20.02.2011
comment
«производительность актуальна»? Как вы думаете, почему понимание списка будет быстрее, чем запись цикла полностью: они не будут измеримой разницей, если у вас есть простое понимание списка. Более сложные искаженные списки могут работать быстрее, если они написаны в виде чистого расширенного кода.   -  person Duncan    schedule 20.02.2011
comment
Мартелли описывает способ, который может работать в Py25 и Py26, в этом дубликате > stackoverflow.com/questions/2638478/   -  person XORcist    schedule 20.02.2011
comment
Взгляните на этот код, но решить совсем другую задачу, которая только у меня в голове — не очень хороший вопрос. Вместо этого просто напишите, что вам действительно нужно. Кстати, функции генератора так же эффективны, как и LC - вы не можете не делать все с LC.   -  person Jochen Ritzel    schedule 20.02.2011
comment
Производительность имеет значение, но вы хотите использовать алгоритм O (N ^ 2), а не O (N).   -  person    schedule 20.02.2011


Ответы (4)


Раньше был способ сделать это, используя недокументированный факт, что пока список строился, его значение сохранялось в локальной переменной с именем _[1].__self__. Однако это перестало работать в Python 2.7 (может быть, раньше, я не обращал особого внимания).

Вы можете делать то, что хотите, в одном понимании списка, если сначала настроите внешнюю структуру данных. Поскольку весь ваш псевдокод, казалось, делал с this_list, проверял его, чтобы убедиться, что каждый s уже был в нем - то есть тест на членство - я изменил его на set с именем seen в качестве оптимизации (проверка на членство в list может быть очень медленным, если список большой). Вот что я имею в виду:

raw_data = [c for c in 'abcdaebfc']

seen = set()
def some_function(s):
    seen.add(s)
    return s

print [ some_function(s) for s in raw_data if s not in seen ]
# ['a', 'b', 'c', 'd', 'e', 'f']

Если у вас нет доступа к some_function, вы можете поместить его вызов в свою собственную функцию-оболочку, которая добавляла возвращаемое значение к набору seen перед его возвратом.

Несмотря на то, что это не будет понимание списка, я бы инкапсулировал все это в функцию, чтобы упростить повторное использование:

def some_function(s):
    # do something with or to 's'...
    return s

def add_unique(function, data):
    result = []
    seen = set(result) # init to empty set
    for s in data:
        if s not in seen:
            t = function(s)
            result.append(t)
            seen.add(t)
    return result

print add_unique(some_function, raw_data)
# ['a', 'b', 'c', 'd', 'e', 'f']

В любом случае мне кажется странным, что список, созданный в вашем псевдокоде, на который вы хотите сослаться, состоит не из подмножества значений raw_data, а скорее из результата вызова some_function для каждого из них, т.е. преобразованных данных. - что, естественно, заставляет задаться вопросом, что делает some_function, чтобы его возвращаемое значение могло совпадать со значением существующего элемента raw_data.

person martineau    schedule 20.02.2011

Я не понимаю, почему вам нужно сделать это за один раз. Либо сначала выполните итерацию по исходным данным, чтобы исключить дубликаты, либо, что еще лучше, преобразуйте их в set, как предлагает KennyTM, - а затем выполните понимание списка.

Обратите внимание, что даже если бы вы могли сослаться на «список в процессе создания», ваш подход все равно потерпит неудачу, потому что s все равно не находится в списке - результат some_function(s) есть.

person Daniel Roseman    schedule 20.02.2011

Насколько я знаю, нет никакого способа получить доступ к пониманию списка по мере его создания.

Как упоминал KennyTM (и если порядок записей не имеет значения), вместо этого вы можете использовать set. Если вы работаете на Python 2.7/3.1 и выше, вы даже получите набор понятий:

{ some_function(s) for s in raw_data }

В противном случае цикл for тоже не так уж плох (хотя он будет ужасно масштабироваться)

l = []
for s in raw_data:
    item = somefunction(s)
    if item not in l:
        l.append(item)
person Tim Pietzcker    schedule 20.02.2011
comment
Другой способ сделать это в старых версиях Python — преобразовать список в набор: set([ some_function(s) for s in raw_data ]) - person Avi; 20.02.2011
comment
опять же — мой псевдокод — это всего лишь пример. Мне не нужны уникальные предметы, это просто артефакт моего примера. Суть в том, что в аккредитиве есть ссылка на «this_list» — это проблема, которую я пытаюсь решить. И вы совершенно правы в отношении того, почему ваш ответ не сработает для меня и почему я избегал его - это модуль ETL, здесь действительно замешан «масштаб». Ясно, что я хочу избежать создания вспомогательных/временных контейнеров, поэтому я очень хочу закодировать аккредитив. - person doug; 20.02.2011
comment
@doug: вы упомянули масштаб, когда отвергли ответ Тима, но is s в this_list вашего предпочтительного решения будет выполняться N раз и будет выполнять O (N) сравнений - мне кажется, что O (N ** 2) все зависит от меня. Насколько велико N? Что вы используете для сравнения двух объектов на эквивалентность? - person John Machin; 20.02.2011

Почему бы вам просто не сделать:[ some_function(s) for s in set(raw_data) ]

Это должно делать то, о чем вы просите. За исключением случаев, когда вам нужно сохранить порядок предыдущего списка.

person jammon    schedule 20.02.2011