Перемістіть список у зворотному порядку в Python


702

Тож я можу починати len(collection)і закінчувати collection[0].

Я також хочу мати доступ до індексу циклу.

Відповіді:


1183

Використовуйте вбудовану reversed()функцію:

>>> a = ["foo", "bar", "baz"]
>>> for i in reversed(a):
...     print(i)
... 
baz
bar
foo

Щоб також отримати доступ до оригінального індексу, використовуйте його enumerate()у своєму списку, перш ніж передати його reversed():

>>> for i, e in reversed(list(enumerate(a))):
...     print(i, e)
... 
2 baz
1 bar
0 foo

Оскільки enumerate()повернення генератора і генераторів неможливо повернути, вам потрібно перетворити його в listперший.


131
Копія не створюється, елементи повертаються на льоту під час руху. Це важлива особливість усіх цих ітераційних функцій (які закінчуються на "ed").
Конрад Рудольф

9
@Greg Hewgill Ні, це ітератор над оригіналом, копія не створюється!
Андре

92
Щоб уникнути плутанини: reversed()список не змінює. reversed()не робить копію списку (інакше це потребує додаткової пам'яті O (N)). Якщо вам потрібно змінити використання списку alist.reverse(); якщо вам потрібна копія списку у зворотному порядку використання alist[::-1].
jfs

91
у цій відповіді, однак, список (перерахувати (а)) створює копію.
Триптих

43
@ JF, перевернутий () не робить копію, але список (перерахувати ()) НЕ робить копію.
Триптих

172

Ви можете зробити:

for item in my_list[::-1]:
    print item

(Або все, що ви хочете зробити в циклі for.)

[::-1]Скибочки перевертає список в циклі для (але не буде на самому ділі змінити свій список «постійно»).


24
[::-1]створює неглибоку копію, тому він не змінює масив ні "постійно", ні "тимчасово".
jfs

6
Це трохи повільніше, ніж використання зворотного, принаймні під Python 2.7 (тестовано).
kgriffs

14
Як працює ця відповідь : вона створює нарізану копію списку з параметрами: початкова точка : невизначена (стає довжиною списку так починається в кінці), кінцева точка : не вказана (стає деяким магічним числом, окрім 0, мабуть -1, і закінчується на початку ) та крок : -1(повторюється назад через список, 1пункт за часом).
Едвард

1
Я також тестував це (python 2.7), і це було ~ 10% повільніше, щоб використовувати [:: - 1] протиreversed()
RustyShackleford

67

Якщо вам потрібен індекс циклу, і ви не хочете двічі обходити весь список або використовувати додаткову пам'ять, я б написав генератор.

def reverse_enum(L):
   for index in reversed(xrange(len(L))):
      yield index, L[index]

L = ['foo', 'bar', 'bas']
for index, item in reverse_enum(L):
   print index, item

3
Я б назвав функцію enumerate_reversed, але це може бути лише мій смак. Я вважаю, що ваша відповідь є найбільш чистою для конкретного питання.
tzot

1
reversed(xrange(len(L)))виробляє ті ж показники, що і xrange(len(L)-1, -1, -1).
jfs

2
Я вважаю за краще менше рухомих частин, щоб зрозуміти:for index, item in enumerate(reversed(L)): print len(L)-1-index, item
Дон Кіркбі

2
@Triptych Мені просто довелося впоратися з тим, що перерахування з reversed () не призведе до зворотних індексів, і ваш код дуже допоміг. Цей метод повинен бути в стандартній бібліотеці.
oski86

2
reversed (xrange ()) працює тому, що в об'єкті xrange використовується метод __reversed__, а також методи __len__ та __getitem__, і зворотний може виявити це та використовувати їх. Але перелічуваний об'єкт не має __reversed__, __len__ або __getitem__. Але чому їх не перелічити? Я цього не знаю.
FutureNerd

60

Це можна зробити так:

для i в діапазоні (len (колекція) -1, -1, -1):
    колекція друку [i]

    # print (колекція [i]) для python 3. +

Тож ваша здогадка була досить близькою :) Трохи незручно, але це в основному говорить: почніть з 1 менше len(collection), продовжуйте, поки ви не дістанетесь трохи до -1, кроками -1.

Fyi, ця helpфункція дуже корисна, оскільки дозволяє переглядати документи для чогось із консолі Python, наприклад:

help(range)


1
Для версій Python до 3.0, я вважаю, що xrange є кращим для діапазону для великих len (колекція).
Брайан М. Хант

Я вважаю, що ви правильні :) iirc, range () генерує весь діапазон у вигляді масиву, але xrange () повертає ітератор, який генерує значення лише у міру необхідності.
Алан Роварт,

11
Це виглядає занадто дивно з такою кількістю -1's. Я б просто сказавreversed(xrange(len(collection)))
musiphil

22

reversedФункція вбудованої зручно:

for item in reversed(sequence):

Документація для обернено пояснює свої обмеження.

У випадках, коли мені потрібно пройти послідовність в зворотному порядку разом з індексом (наприклад, для змін на місці, що змінюють довжину послідовності), ця функція визначила мій модуль кодекса:

import itertools
def reversed_enumerate(sequence):
    return itertools.izip(
        reversed(xrange(len(sequence))),
        reversed(sequence),
    )

Цей уникає створення копії послідовності. Очевидно, reversedобмеження все ще діють.


9

Як щодо того, щоб не відтворити новий список, ви можете зробити це шляхом індексації:

>>> foo = ['1a','2b','3c','4d']
>>> for i in range(len(foo)):
...     print foo[-(i+1)]
...
4d
3c
2b
1a
>>>

АБО

>>> length = len(foo)
>>> for i in range(length):
...     print foo[length-i-1]
...
4d
3c
2b
1a
>>>

9
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

АБО

>>> print l[::-1]
['d', 'c', 'b', 'a']

7

Мені подобається однолінійний підхід генератора:

((i, sequence[i]) for i in reversed(xrange(len(sequence))))

7

Також ви можете використовувати або функції "діапазон", або "підрахунок". Так:

a = ["foo", "bar", "baz"]
for i in range(len(a)-1, -1, -1):
    print(i, a[i])

3 baz
2 bar
1 foo

Ви також можете використовувати "count" з itertools як наступне:

a = ["foo", "bar", "baz"]
from itertools import count, takewhile

def larger_than_0(x):
    return x > 0

for x in takewhile(larger_than_0, count(3, -1)):
    print(x, a[x-1])

3 baz
2 bar
1 foo

Код у вашому першому блоці там не дає правильного виводу; вихід насправді3 foo\n2 bar\n1 baz
amiller27

Щоб уникнути використання "a [i-1]" у першому прикладі, використовуйте цей діапазон "діапазон (len (a) -1, -1, -1)". Це більш спрощено.
Франциск


4

Підхід без імпорту:

for i in range(1,len(arr)+1):
    print(arr[-i])

або

for i in arr[::-1]:
    print(i)

3
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)

3

тому що ніколи не варто це зробити і так. дуже просто.

a = [1, 2, 3, 4, 5, 6, 7]
for x in xrange(len(a)):
    x += 1
    print a[-x]

1
Ви також можете робити print a[-(x+1)]і уникати перепризначення індексу в тілі циклу.
Малькольм

2

Виразний спосіб досягти reverse(enumerate(collection))в python 3:

zip(reversed(range(len(collection))), reversed(collection))

в пітоні 2:

izip(reversed(xrange(len(collection))), reversed(collection))

Я не впевнений, чому ми не маємо для цього скорочення, наприклад:

def reversed_enumerate(collection):
    return zip(reversed(range(len(collection))), reversed(collection))

або чому у нас його немає reversed_range()


2

Якщо вам потрібен індекс, і ваш список невеликий, найбільш читабельний спосіб - це зробити так, reversed(list(enumerate(your_list)))як говорить прийнята відповідь. Але це створює копію списку, тому якщо ваш список займає значну частину пам’яті, вам доведеться відняти індекс, повернутий enumerate(reversed())з len()-1.

Якщо вам потрібно зробити це один раз:

a = ['b', 'd', 'c', 'a']

for index, value in enumerate(reversed(a)):
    index = len(a)-1 - index

    do_something(index, value)

або якщо вам потрібно зробити це кілька разів, ви повинні використовувати генератор:

def enumerate_reversed(lyst):
    for index, value in enumerate(reversed(lyst)):
        index = len(lyst)-1 - index
        yield index, value

for index, value in enumerate_reversed(a):
    do_something(index, value)

1

тут корисна функція реверсу:

myArray = [1,2,3,4]
myArray.reverse()
for x in myArray:
    print x

list.reverse () не має значення повернення
Georg Schölly

1

Ви також можете використовувати whileцикл:

i = len(collection)-1
while i>=0:
    value = collection[i]
    index = i
    i-=1

1

Ви можете використовувати негативний індекс у звичайному для циклу:

>>> collection = ["ham", "spam", "eggs", "baked beans"]
>>> for i in range(1, len(collection) + 1):
...     print(collection[-i])
... 
baked beans
eggs
spam
ham

Щоб отримати доступ до індексу, як якщо б ви повторювали перевернуту копію колекції, скористайтеся i - 1:

>>> for i in range(1, len(collection) + 1):
...     print(i-1, collection[-i])
... 
0 baked beans
1 eggs
2 spam
3 ham

Для доступу до оригінального, не перевернутого індексу використовуйте len(collection) - i:

>>> for i in range(1, len(collection) + 1):
...     print(len(collection)-i, collection[-i])
... 
3 baked beans
2 eggs
1 spam
0 ham

1

Якщо ви не заперечуєте, щоб індекс був негативним, ви можете зробити:

>>> a = ["foo", "bar", "baz"]
>>> for i in range(len(a)):
...     print(~i, a[~i]))
-1 baz
-2 bar
-3 foo

1

Я думаю, що найелегантніший спосіб - це перетворення enumerateта reversedвикористання наступного генератора

(-(ri+1), val) for ri, val in enumerate(reversed(foo))

який генерує реверс enumerateітератора

Приклад:

foo = [1,2,3]
bar = [3,6,9]
[
    bar[i] - val
    for i, val in ((-(ri+1), val) for ri, val in enumerate(reversed(foo)))
]

Результат:

[6, 4, 2]

0

Інші відповіді хороші, але якщо ви хочете зробити це як стиль розуміння списку

collection = ['a','b','c']
[item for item in reversed( collection ) ]

1
Хіба це не те саме, що перевернутий (колекція)? Додавання розуміння списку не робить нічого, крім зайвих обчислень. Це як записувати a = [елемент для елемента в [1, 2, 3]] vs a = [1, 2, 3].
EpicDavi

0

Щоб використовувати негативні показники: починайте з -1 та відступайте від -1 при кожній ітерації.

>>> a = ["foo", "bar", "baz"]
>>> for i in range(-1, -1*(len(a)+1), -1):
...     print i, a[i]
... 
-1 baz
-2 bar
-3 foo

0

Простий спосіб:

n = int(input())
arr = list(map(int, input().split()))

for i in reversed(range(0, n)):
    print("%d %d" %(i, arr[i]))

0
input_list = ['foo','bar','baz']
for i in range(-1,-len(input_list)-1,-1)
    print(input_list[i])

я думаю, що це також простий спосіб зробити це ... читати з кінця і тримати зменшення до довжини списку, оскільки ми ніколи не виконуємо індекс "кінця", отже додаємо -1 також


0

Припустимо, що завдання полягає в тому, щоб знайти останній елемент, який задовольняє певній умові у списку (тобто спочатку, коли я дивлюся назад), я отримую такі цифри:

>>> min(timeit.repeat('for i in xrange(len(xs)-1,-1,-1):\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', repeat=8))
4.6937971115112305
>>> min(timeit.repeat('for i in reversed(xrange(0, len(xs))):\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', repeat=8))
4.809093952178955
>>> min(timeit.repeat('for i, x in enumerate(reversed(xs), 1):\n    if 128 == x: break', setup='xs, n = range(256), 0', repeat=8))
4.931743860244751
>>> min(timeit.repeat('for i, x in enumerate(xs[::-1]):\n    if 128 == x: break', setup='xs, n = range(256), 0', repeat=8))
5.548468112945557
>>> min(timeit.repeat('for i in xrange(len(xs), 0, -1):\n    if 128 == xs[i - 1]: break', setup='xs, n = range(256), 0', repeat=8))
6.286104917526245
>>> min(timeit.repeat('i = len(xs)\nwhile 0 < i:\n    i -= 1\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', repeat=8))
8.384078979492188

Отже, найгірший варіант xrange(len(xs)-1,-1,-1)- найшвидший.


-1

Ви можете використовувати генератор:

li = [1,2,3,4,5,6]
len_li = len(li)
gen = (len_li-1-i for i in range(len_li))

нарешті:

for i in gen:
    print(li[i])

сподіваюся, що це допоможе тобі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.