Рекурсивное понимание списка в Python?
Можно ли определить рекурсивное понимание списка в Python?
Возможно, упрощенный пример, но что-то вроде:
nums = [1, 1, 2, 2, 3, 3, 4, 4]
willThisWork = [x for x in nums if x not in self] # self being the current comprehension
Возможно ли подобное?
Ответы
Ответ 1
Нет, нет (документированный, прочный, стабильный,...;-) способ ссылаться на "текущее понимание". Вы можете просто использовать цикл:
res = []
for x in nums:
if x not in res:
res.append(x)
конечно, это очень дорого (O (квадрат N)), поэтому вы можете оптимизировать его с помощью вспомогательного set
(я предполагаю, что сохранение порядка элементов в res
конгруэнтно по отношению к элементам в nums
, в противном случае set(nums)
сделает вас; -)...:
res = []
aux = set()
for x in nums:
if x not in aux:
res.append(x)
aux.add(x)
это очень быстро для очень длинных списков (O (N) вместо квадратов N).
Изменить: в Python 2.5 или 2.6, vars()['_[1]']
может действительно работать в той роли, которую вы хотите для self
(для не-вложенного listcomp)... вот почему я определил свой, прояснив там документированный, надежный, стабильный способ доступа к "составленному списку" - это своеобразное недокументированное "имя" '_[1]'
(намеренно выбранное не является допустимым идентификатором; ) является вершиной "артефактов реализации", и любой используемый на ней код заслуживает того, чтобы его портили, -).
Ответ 2
Собственно вы можете! Этот пример с объяснением, надеюсь, проиллюстрирует, как это сделать.
Определите рекурсивный пример, чтобы получить число, только если оно равно 5 или больше, а если нет, увеличьте его и снова вызовите функцию проверки. Повторите этот процесс, пока он не достигнет 5, в этот момент верните 5.
print [ (lambda f,v: v >= 5 and v or f(f,v+1))(lambda g,i: i >= 5 and i or g(g,i+1),i) for i in [1,2,3,4,5,6] ]
результат:
[5, 5, 5, 5, 5, 6]
>>>
по существу две анонимные функции взаимодействуют таким образом:
let f(g,x) = {
expression, terminal condition
g(g,x), non-terminal condition
}
let g(f,x) = {
expression, terminal condition
f(f,x), non-terminal condition
}
сделать g, f "той же" функцией, за исключением того, что в одном или обоих добавьте предложение, в котором параметр изменен, чтобы вызвать условие терминала, и затем перейти
f (g, x) таким образом, g становится копией f, которая делает это следующим образом:
f(g,x) = {
expression, terminal condition
{
expression, terminal condition,
g(g,x), non-terminal codition
}, non-terminal condition
}
Вам нужно сделать это, потому что вы не можете получить доступ к анонимной функции при ее выполнении.
i.e
(lambda f,v: somehow call the function again inside itself )(_,_)
поэтому в этом примере пусть A = первая функция, а B - вторая. Мы называем A проходящим B как f и я как v. Теперь, когда B является по существу копией A, и это переданный параметр, вы можете теперь называть B, который похож на вызов A.
Это генерирует факториалы в списке
print [ (lambda f,v: v == 0 and 1 or v*f(f,v-1))(lambda g,i: i == 0 and 1 or i*g(g,i-1),i) for i in [1,2,3,5,6,7] ]
[1, 2, 6, 120, 720, 5040]
>>>
Ответ 3
нет. он не будет работать, не существует self
для ссылки, пока выполняется выполнение списка.
И главная причина, конечно, в том, что списки, которые не предназначены для этого использования.
Ответ 4
Не уверен, что это то, что вы хотите, но вы можете писать вложенные списки:
xs = [[i for i in range(1,10) if i % j == 0] for j in range(2,5)]
assert xs == [[2, 4, 6, 8], [3, 6, 9], [4, 8]]
Из вашего примера кода вы, похоже, хотите просто удалить дубликаты, которые вы можете делать с наборами:
xs = sorted(set([1, 1, 2, 2, 3, 3, 4, 4]))
assert xs == [1, 2, 3, 4]
Ответ 5
Нет.
Но похоже, что вы пытаетесь составить список уникальных элементов в nums.
Вы можете использовать set
:
unique_items = set(nums)
Обратите внимание, что элементы в числах должны быть хешируемыми.
Вы также можете сделать следующее. Который близко, поскольку я могу добраться до вашей оригинальной идеи. Но это не так эффективно, как создание set
.
unique_items = []
for i in nums:
if i not in unique_items:
unique_items.append(i)
Ответ 6
Сделайте это:
nums = [1, 1, 2, 2, 3, 3, 4, 4]
set_of_nums = set(nums)
unique_num_list = list(set_of_nums)
или даже это:
unique_num_list = sorted(set_of_nums)
Ответ 7
Начиная с Python 3.8
и введением выражений присваивания (PEP 572) (:=
оператор), который дает возможность назвать результат выражения, мы могли бы ссылаться на уже увиденные элементы, обновляя переменную в пределах понимания списка:
# items = [1, 1, 2, 2, 3, 3, 4, 4]
acc = []; [acc := acc + [x] for x in items if x not in acc]
# acc = [1, 2, 3, 4]
Это:
- Инициализирует список в соответствии с
acc
списком уже просмотренных элементов. - Для каждого элемента, это проверяет, если он уже часть
acc
список; а если нет: - добавляет элемент к
acc
(acc := acc + [x]
) через выражение присваивания - и в то же время использует новое значение
acc
как сопоставленное значение для этого элемента