почему я не могу перевернуть список в Python - PullRequest
11 голосов
/ 25 сентября 2010

Я хотел сделать что-то подобное, но этот код возвращает список None (я думаю, это потому, что list.reverse () переворачивает список на месте):

map(lambda row: row.reverse(), figure)

Я попробовал это, но обратный возвращает итератор:

map(reversed, figure)

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

def reverse(row):
    """func that reverse a list not in place"""
    row.reverse()
    return row

map(reverse, figure)

если у кого-то есть лучшее решение, о котором я не знаю, пожалуйста, дайте мне знать

С уважением,

Ответы [ 5 ]

27 голосов
/ 25 сентября 2010

Методы mutator изменчивых контейнеров Python (такие как метод списков .reverse) почти всегда возвращают None - некоторые возвращают одно полезное значение, например, метод .pop возвращает извлеченный элемент, но ключевая концепция, которую следует сохранить, заключается в том, что ни один из этих мутаторов не возвращает мутировавший контейнер: скорее, контейнер мутирует на месте , а возвращаемое значение метода мутатора равно не этот контейнер. (Это применение принципа CQS - не настолько фанатичного, как, скажем, в Eiffel, языке, разработанном Бертраном Мейером, который также изобрел CQS, но это только потому, что в Python "практичность" бьет чистотой, ср import this; -).

Построение списка часто обходится дороже, чем просто создание итератора, поскольку в подавляющем большинстве случаев вам нужно всего лишь loop для результата; поэтому встроенные модули, такие как reversed (и все замечательные строительные блоки в модуле itertools), возвращают итераторы, списки , а не .

Но что, если у вас есть итератор x, но вам действительно нужен эквивалентный список y? Кусок торта - просто сделай y = list(x). Чтобы создать новый экземпляр типа list, вы вызываете типа list - это такая общая идея Python, что даже более важно сохранить ее, чем довольно важный материал, который я указал в первые два абзаца! -)

Итак, код для вашей конкретной задачи действительно очень легко составить, основываясь на ключевых понятиях в предыдущих параграфах:

[list(reversed(row)) for row in figure]

Обратите внимание, что я использую понимание списка, не map: как правило, map следует использовать только в качестве последней оптимизации, когда нет требуется lambda для его построения (если задействован lambda, то listcomp, а также более ясный, как обычно, также в любом случае быстрее! -).

Как только вы станете «бывшим мастером Python», если ваше профилирование говорит вам, что этот код является узким местом, вы можете попробовать другие варианты, такие как

[row[::-1] for row in figure]

применяя нарезку с отрицательным шагом (также известную как "Марсианский смайлик"), чтобы сделать перевернутые копии строк, зная, что это обычно быстрее, чем подход list(reversed(row)). Но - если ваш код не предназначен для поддержки только вами или кем-то, по крайней мере, столь же опытным в Python - это оправданная позиция, чтобы использовать простейший подход «код из первых принципов», за исключением случаев, когда профилирование подсказывает вам нажать на педаль , (Лично я думаю, что «Марсианский смайлик» достаточно важен, чтобы не применять эту хорошую общую философию к этому конкретному случаю использования, но разумные люди могут отличаться по этому очень специфическому вопросу!

8 голосов
/ 25 сентября 2010

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

>>> a = [1,2,3,4]
>>> a[::-1]
[4, 3, 2, 1]

Так что-то вроде:

all_reversed = [lst[::-1] for lst in figure]

... или ...

all_reversed = map(lambda x: x[::-1], figure)

... будет делать то, что вы хотите.

3 голосов
/ 25 сентября 2010
reversed_lists = [list(reversed(x)) for x in figure]
1 голос
/ 25 сентября 2010
map(lambda row: list(reversed(row)), figure)
0 голосов
/ 25 сентября 2010

Вы также можете просто сделать

for row in figure:
    row.reverse()

для изменения каждой строки на месте.

...