Список понимания Python - PullRequest
2 голосов
/ 14 июля 2009

Что такое эквивалентное понимание списка в python следующего кода Common Lisp:

(loop for x = input then (if (evenp x)
                             (/ x 2)
                             (+1 (* 3 x)))
      collect x
      until (= x 1))

Ответы [ 6 ]

10 голосов
/ 14 июля 2009

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

numbers = []
x=input()
while x != 1:
  numbers.append(x)
  if x % 2 == 0: x /= 2
  else: x = 3 * x + 1
9 голосов
/ 14 июля 2009

Полагаю, вы пишете последовательность града, хотя я могу ошибаться, поскольку я не бегло говорю на Лиспе.

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

Как бы я сделал это было бы

def hailstone(n):
    yield n
    while n!=1
        if n%2 == 0: # even
            n = n / 2
        else: # odd
            n = 3 * n + 1
        yield n

list = [ x for x in hailstone(input) ]

Конечно, ввод будет содержать любой ввод.

Моя функция града, вероятно, может быть более краткой. Моей целью была ясность.

4 голосов
/ 14 июля 2009

Взлом, на который ссылается Лоуренс:

Вы можете сделать это в одном понимании списка, это просто заканчивается УДОВОЛЬСТВЕННЫМ питоном. Нечитаемый питон. Страшный питон. Я только представляю следующее как любопытство, а не как фактический ответ. Не делайте этого в коде, который вы на самом деле хотите использовать, только если вы хотите поиграть с внутренней работой на python.

Итак, 3 подхода:


Список помощи 1

1: Используя список помощи, ответ заканчивается в списке помощи. Это добавляет значения в список, который повторяется до тех пор, пока вы не достигнете значения, на котором хотите остановиться.

A = [10]
print [None if A[-1] == 1
    else A.append(A[-1]/2) if (A[-1]%2==0) 
    else A.append(3*A[-1]+1) 
        for i in A]
print A

результат:

[None, None, None, None, None, None, None]
[10, 5, 16, 8, 4, 2, 1]

Список помощи 2

2: Использование списка помощи, но с результатом, являющимся результатом понимания списка. В основном это зависит от list.append(...), возвращающего None, not None с оценкой True и True, считающейся 1 для целей арифметики Вздох.

A=[10]
print [A[0]*(not A.append(A[0])) if len(A) == 1 
    else 1 if A[-1] == 2 else (A[-1]/2)*(not A.append(A[-1]/2)) if (A[-1]%2==0) 
    else (3*A[-1]+1)*(not A.append(3*A[-1]+1)) 
        for i in A]

результат:

[10, 5, 16, 8, 4, 2, 1]

Ссылка на понимание списка изнутри

3: Не использовать список помощи, а возвращаться к пониманию списка по мере его создания. Это немного хрупко, и, вероятно, не будет работать во всех средах. Если это не работает, попробуйте запустить код самостоятельно:

from itertools import chain, takewhile
initialValue = 10
print [i if len(locals()['_[1]']) == 0
    else (locals()['_[1]'][-1]/2) if (locals()['_[1]'][-1]%2==0)
    else (3*locals()['_[1]'][-1]+1) 
        for i in takewhile(lambda x:x>1, chain([initialValue],locals()['_[1]']))]

результат:

[10, 5, 16, 8, 4, 2, 1]

Итак, теперь забудьте, что вы читали это. Это темный, темный и грязный питон. Злой питон. И мы все знаем, что питон не злой. Питон милый и приятный. Так что вы не могли прочитать это, потому что такого рода вещи не могут существовать. Хорошо хорошо.

4 голосов
/ 14 июля 2009

Python не имеет встроенной структуры управления такого типа, но вы можете обобщить это в функцию, подобную этой:

def unfold(evolve, initial, until):
    state = initial
    yield state
    while not until(state):
        state = evolve(state)
        yield state

После этого ваше выражение может быть записано как:

def is_even(n): return not n % 2
unfold(lambda x: x/2 if is_even(x) else 3*x + 1,
       initial=input, until=lambda x: x == 1)

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

def produce(x):
    yield x
    while x != 1:
        x = x / 2 if is_even(x) else 3*x + 1
        yield x
3 голосов
/ 14 июля 2009

Как сказал Кив, для понимания списка требуется итерация по известной последовательности.

Сказав, что, если у вас есть последовательность и вы сосредоточены на использовании понимания списка, ваше решение, вероятно, будет включать что-то вроде этого:

[not (x % 2) and (x / 2) or (3 * x + 1) for x in sequence]

Ответ Майка Купера - лучшее решение, так как он сохраняет окончание x != 1, и эта строка не читается правильно.

0 голосов
/ 14 июля 2009

1

Я обнаружил поистине изумительное доказательство этого, которое слишком узко для этого поля.

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

...