Di chuyển một danh sách theo thứ tự ngược lại trong Python


701

Vì vậy, tôi có thể bắt đầu từ len(collection)và kết thúc collection[0].

Tôi cũng muốn có thể truy cập vào chỉ số vòng lặp.

Câu trả lời:


1181

Sử dụng reversed()chức năng tích hợp:

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

Để truy cập chỉ mục gốc, hãy sử dụng enumerate()trong danh sách của bạn trước khi chuyển nó tới reversed():

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

enumerate()trả về một máy phát và máy phát không thể đảo ngược, bạn cần chuyển đổi nó thành máy phát listtrước.


130
Không có bản sao được tạo ra, các yếu tố được đảo ngược trong khi di chuyển! Đây là một tính năng quan trọng của tất cả các chức năng lặp này (tất cả đều kết thúc trên bản ed ed).
Konrad Rudolph

9
@Greg Hewgill Không, đó là trình lặp so với bản gốc, không có bản sao nào được tạo!
André

92
Để tránh nhầm lẫn: reversed()không sửa đổi danh sách. reversed()không tạo một bản sao của danh sách (nếu không nó sẽ yêu cầu bộ nhớ bổ sung O (N)). Nếu bạn cần sửa đổi danh sách sử dụng alist.reverse(); nếu bạn cần một bản sao của danh sách theo thứ tự đảo ngược sử dụng alist[::-1].
jfs

90
trong câu trả lời này, liệt kê (liệt kê (a)) KHÔNG tạo một bản sao.
Triptych

42
@ JF, đảo ngược () không tạo một bản sao, nhưng liệt kê (liệt kê ()) KHÔNG tạo một bản sao.
Triptych

172

Bạn có thể làm:

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

(Hoặc bất cứ điều gì bạn muốn làm trong vòng lặp for.)

Các [::-1]lát cắt đảo ngược danh sách trong vòng lặp for (nhưng thực tế sẽ không sửa đổi danh sách của bạn "vĩnh viễn").


24
[::-1]tạo một bản sao nông, do đó nó không thay đổi mảng không "vĩnh viễn" hay "tạm thời".
jfs

6
Điều này chậm hơn một chút so với sử dụng đảo ngược, ít nhất là theo Python 2.7 (đã thử nghiệm).
kgriffs

14
Cách câu trả lời này hoạt động : nó tạo ra một bản sao của danh sách được cắt lát với các tham số: điểm bắt đầu : không xác định (trở thành độ dài của danh sách bắt đầu từ cuối), điểm cuối : không xác định (trở thành một số phép thuật khác 0, có thể -1, vì vậy kết thúc khi bắt đầu ) và bước : -1(lặp lại qua danh sách, 1mục tại một thời điểm).
Edward

1
Tôi cũng đã thử nghiệm điều này (python 2.7) và nó chậm hơn ~ 10% khi sử dụng [:: - 1] so vớireversed()
RustyShackleford

67

Nếu bạn cần chỉ mục vòng lặp và không muốn duyệt qua toàn bộ danh sách hai lần hoặc sử dụng thêm bộ nhớ, tôi sẽ viết một trình tạo.

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
Tôi sẽ gọi hàm enum Cả numversed, nhưng đó có thể chỉ là sở thích của tôi. Tôi tin rằng câu trả lời của bạn là sạch nhất cho câu hỏi cụ thể.
tzot

1
reversed(xrange(len(L)))tạo ra các chỉ số tương tự như xrange(len(L)-1, -1, -1).
jfs

2
Tôi thích ít bộ phận chuyển động hơn để hiểu:for index, item in enumerate(reversed(L)): print len(L)-1-index, item
Don Kirkby

2
@Triptych Tôi vừa phải đối phó với thực tế là liệt kê từ đảo ngược () sẽ không mang lại các chỉ số đảo ngược và mã của bạn đã giúp rất nhiều. Phương pháp này nên có trong thư viện tiêu chuẩn.
oski86 21/07/2015

2
đảo ngược (xrange ()) hoạt động vì một đối tượng xrange có phương thức __Vversed__ cũng như các phương thức __len__ và __getitem__ và đảo ngược có thể phát hiện ra điều đó và sử dụng chúng. Nhưng một đối tượng liệt kê không có __Vversed__, __len__ hoặc __getitem__. Nhưng tại sao không liệt kê có chúng? Tôi không biết điều đó.
FutureNerd

60

Nó có thể được thực hiện như thế này:

cho i trong phạm vi (len (bộ sưu tập) -1, -1, -1):
    bộ sưu tập in [i]

    # in (bộ sưu tập [i]) cho python 3. +

Vì vậy, dự đoán của bạn đã khá gần :) Một chút lúng túng nhưng về cơ bản nó nói: bắt đầu với 1 ít hơn len(collection), tiếp tục cho đến khi bạn đến ngay trước -1, theo các bước của -1.

Fyi, helpchức năng này rất hữu ích vì nó cho phép bạn xem các tài liệu cho một cái gì đó từ bảng điều khiển Python, ví dụ:

help(range)


1
Đối với các phiên bản Python trước 3.0, tôi tin rằng xrange thích hợp hơn cho phạm vi len lớn (bộ sưu tập).
Brian M. Hunt

Tôi tin rằng bạn đã đúng :) iirc, phạm vi () tạo toàn bộ phạm vi dưới dạng một mảng nhưng xrange () trả về một trình vòng lặp chỉ tạo ra các giá trị khi cần thiết.
Alan Rowarth

11
Điều này có vẻ quá kỳ lạ với rất nhiều -1. Tôi chỉ muốn nóireversed(xrange(len(collection)))
musiphil

22

Hàm reverseddựng sẵn rất tiện dụng:

for item in reversed(sequence):

Các tài liệu cho đảo ngược giải thích những hạn chế của nó.

Đối với các trường hợp tôi phải đi ngược lại trình tự cùng với chỉ mục (ví dụ: để sửa đổi tại chỗ thay đổi độ dài chuỗi), tôi có chức năng này xác định mô-đun codeutil của tôi:

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

Điều này tránh tạo ra một bản sao của chuỗi. Rõ ràng, những reversedhạn chế vẫn được áp dụng.


9

Làm thế nào về mà không tạo lại một danh sách mới, bạn có thể làm bằng cách lập chỉ mục:

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

HOẶC LÀ

>>> 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']

HOẶC LÀ

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

7

Tôi thích cách tiếp cận máy phát điện một lớp:

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

7

Ngoài ra, bạn có thể sử dụng các hàm "phạm vi" hoặc "đếm". Như sau:

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

3 baz
2 bar
1 foo

Bạn cũng có thể sử dụng "đếm" từ itertools như sau:

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

Mã trong khối đầu tiên của bạn ở đó không tạo ra đầu ra đúng; đầu ra thực sự là3 foo\n2 bar\n1 baz
amiller27

Để tránh sử dụng "a [i-1]" trong ví dụ đầu tiên, hãy sử dụng phạm vi này "phạm vi (len (a) -1, -1, -1)". Điều này được đơn giản hóa hơn.
Francisc


4

Một cách tiếp cận không có nhập khẩu:

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

hoặc là

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

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

3

cho những gì đáng giá bạn cũng có thể làm như thế này. rất đơn giản.

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

1
Bạn cũng có thể làm print a[-(x+1)]và tránh gán lại chỉ số trong phần thân của vòng lặp.
Malcolm

2

Một cách biểu cảm để đạt được reverse(enumerate(collection))trong python 3:

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

trong trăn 2:

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

Tôi không chắc tại sao chúng ta không có một tốc ký cho việc này, vd.:

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

hoặc tại sao chúng ta không có reversed_range()


2

Nếu bạn cần chỉ mục và danh sách của bạn nhỏ, cách dễ đọc nhất là làm reversed(list(enumerate(your_list)))như câu trả lời được chấp nhận nói. Nhưng điều này tạo ra một bản sao của danh sách của bạn, vì vậy nếu danh sách của bạn chiếm một phần lớn bộ nhớ, bạn sẽ phải trừ chỉ mục được trả về enumerate(reversed())từlen()-1 .

Nếu bạn chỉ cần làm một lần:

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

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

    do_something(index, value)

hoặc nếu bạn cần làm điều này nhiều lần, bạn nên sử dụng một trình tạo:

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

chức năng đảo ngược có ích ở đây:

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

list.reverse () không có giá trị trả về
Georg Schölly

1

Bạn cũng có thể sử dụng một whilevòng lặp:

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

1

Bạn có thể sử dụng một chỉ mục tiêu cực trong một vòng lặp for thông thường:

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

Để truy cập vào chỉ mục như thể bạn đang lặp đi lặp lại qua một bản sao đảo ngược của bộ sưu tập, hãy sử dụng i - 1:

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

Để truy cập chỉ mục gốc, không đảo ngược, sử dụng 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

Nếu bạn không nhớ chỉ số là âm, bạn có thể làm:

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

1

Tôi nghĩ rằng cách thanh lịch nhất là chuyển đổi enumeratereversedsử dụng trình tạo sau

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

tạo ra sự đảo ngược của enumeratetrình vòng lặp

Thí dụ:

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)))
]

Kết quả:

[6, 4, 2]

0

Các câu trả lời khác là tốt, nhưng nếu bạn muốn làm theo kiểu hiểu danh sách

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

1
Đây không phải là giống như đảo ngược (bộ sưu tập)? Thêm danh sách hiểu không làm gì, ngoại trừ tính toán không cần thiết. Nó giống như viết a = [mục cho mục trong [1, 2, 3]] vs a = [1, 2, 3].
EpicDavi

0

Để sử dụng các chỉ số phủ định: bắt đầu ở -1 và lùi lại -1 ở mỗi lần lặp.

>>> 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

Một cách đơn giản:

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])

Tôi nghĩ rằng đây cũng là một cách đơn giản để làm điều đó ... đọc từ cuối và tiếp tục giảm dần cho đến khi danh sách kéo dài, vì chúng tôi không bao giờ thực hiện chỉ số "kết thúc" do đó cũng thêm -1


0

Giả sử nhiệm vụ là tìm phần tử cuối cùng thỏa mãn một số điều kiện trong danh sách (nghĩa là lần đầu tiên khi nhìn về phía sau), tôi nhận được các số sau:

>>> 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

Vì vậy, lựa chọn xấu nhất xrange(len(xs)-1,-1,-1)là nhanh nhất.


-1

bạn có thể sử dụng một máy phát điện:

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

cuối cùng:

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

Hy vọng điều này sẽ giúp bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.