Có cần phạm vi (len (a)) không?


83

Người ta thường tìm thấy các biểu thức thuộc loại này trong các câu hỏi python trên SO. Hoặc chỉ để truy cập tất cả các mục của tệp có thể lặp lại

for i in range(len(a)):
    print(a[i])

Đó chỉ là một cách viết rườm rà:

for e in a:
    print(e)

Hoặc để gán cho các phần tử của có thể lặp lại:

for i in range(len(a)):
    a[i] = a[i] * 2

Cái nào phải giống như:

for i, e in enumerate(a):
     a[i] = e * 2
# Or if it isn't too expensive to create a new iterable
a = [e * 2 for e in a]

Hoặc để lọc qua các chỉ số:

for i in range(len(a)):
    if i % 2 == 1: continue
    print(a[i])

Có thể được diễn đạt như thế này:

for e in a [::2]:
    print(e)

Hoặc khi bạn chỉ cần độ dài của danh sách chứ không cần nội dung của nó:

for _ in range(len(a)):
    doSomethingUnrelatedToA()

Có thể là:

for _ in a:
    doSomethingUnrelatedToA()

Trong python chúng tôi có enumerate, cắt lát filter, sorted, vv ... Như trăn forcấu trúc nhằm lặp trên iterables và không chỉ dao động của số nguyên, là có thực tế trường hợp sử dụng khi bạn cần in range(len(a))?


5
Tôi nghĩ range(len(a))thường là những người khá thiếu kinh nghiệm với Python (mặc dù không nhất thiết với lập trình nói chung).
rlms

Tôi chỉ sử dụng range(len(a))khi tôi đang học Python. Ngày nay, tôi không vì, như bạn đã nói, nó khá dễ thay thế.

không hẳn vậy. Tôi sử dụng range(len(a))thường xuyên, vì tôi không cần nội dung của danh sách a, mà chỉ cần độ dài.
aIKid

8
Điều gì sẽ xảy ra nếu trong vòng lặp tôi cần truy cập phần tử trước và sau phần tử hiện tại? Tôi thường có for i in range(len(a)): doSomethingAbout(a[i+1] - a[i])Làm thế nào để vượt qua điều đó?
Zhang18

1
@ JaakkoSeppälä đồng ý. Tôi chỉ đưa ra một ví dụ để minh họa vấn đề chính của việc phải lặp qua các chỉ số, không chỉ các giá trị, hiểu rằng có một trường hợp góc ở cuối bên cạnh điểm chính.
Zhang18

Câu trả lời:


17

Nếu bạn cần làm việc với các chỉ số của một chuỗi, thì có - bạn sử dụng nó ... ví dụ: tương đương với numpy.argsort ...:

>>> a = [6, 3, 1, 2, 5, 4]
>>> sorted(range(len(a)), key=a.__getitem__)
[2, 3, 1, 5, 4, 0]

OK, điều này có vẻ hợp lý. Cảm ơn rât nhiều. Nhưng câu hỏi đặt ra là: bạn sẽ làm gì với danh sách chỉ số mới được sắp xếp của mình. Nếu thông qua danh sách này một lần nữa, bạn truy cập vào một số có thể lặp lại, con chó sẽ tự cắn đuôi của mình.
Hyperboreus

1
Tương đương với: [ix for ix, _ in sorted(enumerate(a), key=lambda i: i[1])]mặc dù, mặc dù của bạn được cho là đẹp hơn / geekier.
Erik Kaplun

10

Điều gì sẽ xảy ra nếu bạn cần truy cập đồng thời hai phần tử của danh sách?

for i in range(len(a[0:-1])):
    something_new[i] = a[i] * a[i+1]

Bạn có thể sử dụng điều này, nhưng nó có thể ít rõ ràng hơn:

for i, _ in enumerate(a[0:-1]):
     something_new[i] = a[i] * a[i+1]

Cá nhân tôi cũng không hài lòng 100%!


1
for ix, i in enumerate(a)có vẻ là tương đương, không?
Erik Kaplun 29/07/18

1
Thay vào đó, người ta nên sử dụng theo cặp .
bay cừu vào

Trong những tình huống tôi làm:for a1,a2 in zip(a[:-1],a[1:])
Luca Amerio

7

Câu trả lời ngắn gọn : nói về mặt toán học là không, về mặt thực tế là có, ví dụ như đối với Lập trình có chủ đích.

Về mặt kỹ thuật, câu trả lời sẽ là "không, không cần thiết" bởi vì nó có thể diễn đạt bằng cách sử dụng các cấu trúc khác. Nhưng trong thực tế, tôi sử dụng for i in range(len(a)(hoặc for _ in range(len(a))nếu tôi không cần chỉ mục) để nói rõ rằng tôi muốn lặp lại bao nhiêu lần có các mục trong một chuỗi mà không cần sử dụng các mục trong chuỗi cho bất cứ điều gì.

Vì vậy: "Có cần không?" ? - vâng, tôi cần nó để thể hiện ý nghĩa / mục đích của mã cho mục đích dễ đọc.

Xem thêm: https://en.wikipedia.org/wiki/Intentional_programming

Và rõ ràng, nếu không có bộ sưu tập nào được liên kết với việc lặp lại, for ... in range(len(N))là lựa chọn duy nhất, để không phải dùng đếni = 0; while i < N; i += 1 ...


Những gì có lợi thế for _ in range(len(a))hơn for _ in a?
Hyperboreus

@Hyperboreus: vâng, tôi vừa sửa đổi câu trả lời của mình vài giây trước nhận xét của bạn ... vì vậy tôi đoán sự khác biệt là liệu bạn có muốn thực sự rõ ràng về "lặp lại NHƯ NHIỀU LẦN vì có các mục trong a" trái ngược với "cho mọi phần tử trong a, bất kể nội dung của a" ... vì vậy chỉ là một sắc thái Lập trình có chủ đích.
Erik Kaplun

Cảm ơn bạn cho ví dụ của bạn. Tôi đã đưa nó vào câu hỏi của mình.
Hyperboreus

2
Để có được một danh sách 'hello'với nhiều mặt hàng như trong danh sách a, sử dụngb = ['hello'] * len(a)
steabert

2

Đi theo những ý kiến cũng như kinh nghiệm cá nhân, tôi nói không, không có nhu cầu cho range(len(a)). Mọi thứ bạn có thể làm đều có range(len(a))thể được thực hiện theo cách khác (thường là hiệu quả hơn nhiều).

Bạn đã đưa ra nhiều ví dụ trong bài đăng của mình, vì vậy tôi sẽ không lặp lại chúng ở đây. Thay vào đó, tôi sẽ đưa ra một ví dụ cho những người nói "Điều gì sẽ xảy ra nếu tôi chỉ muốn chiều dài của a, không phải các mục?". Đây là một trong những lần duy nhất bạn có thể cân nhắc sử dụng range(len(a)). Tuy nhiên, ngay cả điều này cũng có thể được thực hiện như vậy:

>>> a = [1, 2, 3, 4]
>>> for _ in a:
...     print True
...
True
True
True
True
>>>

Câu trả lời Clements (như được hiển thị bởi Allik) cũng có thể được làm lại để loại bỏ range(len(a)):

>>> a = [6, 3, 1, 2, 5, 4]
>>> sorted(range(len(a)), key=a.__getitem__)
[2, 3, 1, 5, 4, 0]
>>> # Note however that, in this case, range(len(a)) is more efficient.
>>> [x for x, _ in sorted(enumerate(a), key=lambda i: i[1])]
[2, 3, 1, 5, 4, 0]
>>>

Vì vậy, kết luận, range(len(a))là không cần thiết . Ưu điểm duy nhất của nó là tính dễ đọc (ý định của nó rất rõ ràng). Nhưng đó chỉ là sở thích và kiểu mã.


Cảm ơn rât nhiều. Và một lần nữa, khả năng đọc được (một phần) trong mắt người xem. Tôi giải thích for _ in a:là "Lặp lại trên a nhưng bỏ qua nội dung của nó", nhưng tôi giải thích for _ in range(len(a))là "Lấy độ dài của a, sau đó tạo một số số nguyên có cùng độ dài và cuối cùng bỏ qua nội dung".
Hyperboreus

1
@Hyperboreus - Rất đúng. Nó chỉ là kiểu mã. Mục tiêu của tôi là chỉ ra rằng sẽ không bao giờ có range(len(a))kịch bản "Tôi phải sử dụng hoặc tôi không thể làm điều này".

Một lưu ý nhỏ: Ví dụ: trong erlang, dấu gạch dưới đơn là biến ẩn danh. Đây là biến duy nhất có thể được gán lại (hoặc "khớp"), không giống như các biến khác, vì erlang không cho phép gán phá hủy (nói chung là một sự ghê tởm và làm suy yếu bức màn giữa chúng ta và các cõi khác, nơi HE chờ đợi sau bức tường trong cung điện được xây bằng thủy tinh bị tra tấn).
Hyperboreus

2

Đôi khi matplotlib yêu cầu range(len(y)), ví dụ, trong khi y=array([1,2,5,6]), plot(y)hoạt động tốt, scatter(y)không. Người ta phải viết scatter(range(len(y)),y). (Cá nhân tôi nghĩ rằng đây là một lỗi trong scatter; plotvà những người bạn của nó scatterstemnên sử dụng các chuỗi gọi giống nhau càng nhiều càng tốt.)


2

Thật tuyệt khi bạn cần sử dụng chỉ mục cho một số loại thao tác và có phần tử hiện tại là không đủ. Lấy ví dụ một cây nhị phân được lưu trữ trong một mảng. Nếu bạn có một phương thức yêu cầu bạn trả về một danh sách các bộ giá trị chứa mỗi nút con trực tiếp thì bạn cần chỉ mục.

#0 -> 1,2 : 1 -> 3,4 : 2 -> 5,6 : 3 -> 7,8 ...
nodes = [0,1,2,3,4,5,6,7,8,9,10]
children = []
for i in range(len(nodes)):
  leftNode = None
  rightNode = None
  if i*2 + 1 < len(nodes):
    leftNode = nodes[i*2 + 1]
  if i*2 + 2 < len(nodes):
    rightNode = nodes[i*2 + 2]
  children.append((leftNode,rightNode))
return children

Tất nhiên nếu phần tử bạn đang làm việc là một đối tượng, bạn chỉ có thể gọi một phương thức get children. Nhưng vâng, bạn chỉ thực sự cần chỉ mục nếu bạn đang thực hiện một số thao tác.


1

Tôi có một trường hợp sử dụng Tôi không tin rằng bất kỳ ví dụ nào của bạn bao gồm.

boxes = [b1, b2, b3]
items = [i1, i2, i3, i4, i5]
for j in range(len(boxes)):
    boxes[j].putitemin(items[j])

Tôi tương đối mới với python mặc dù rất vui khi tìm hiểu một cách tiếp cận đơn giản hơn.


4
Sự ngu dốt của tôi. Có zip, một cách phức tạp hơn nhiều để lặp lại 2 danh sách song song.
Jim,

1
Hah, tôi đến đây với một trường hợp sử dụng thực sự tương tự ... [a - b for a, b in zip(list1, list2)]đẹp hơn rất nhiều so với [list1[i] - list2[i] for i in range(len(list1))].. Cảm ơn!
kevlarr 17/02/17

1

Nếu bạn phải lặp lại các len(a)mục đầu tiên của một đối tượng b(lớn hơn a), bạn có thể nên sử dụng range(len(a)):

for i in range(len(a)):
    do_something_with(b[i])

2
Điều này có thể rõ ràng hơn:for b_elem in b[:len(a)]:...
aquirdturtle

@aquirdturtle Có lẽ nó rõ ràng hơn, nhưng giải pháp của bạn tạo ra một danh sách mới, có thể tốn kém nếu b & a lớn.
Chiều 2 giờ

Điều này nên được xử lý bằng cách sử dụng itertools.islicethay thế.
MisterMiyagi

1

Đôi khi, bạn thực sự không quan tâm đến chính bộ sưu tập . Ví dụ: tạo một dòng phù hợp với mô hình đơn giản để so sánh "ước lượng" với dữ liệu thô:

fib_raw = [1, 1, 2, 3, 5, 8, 13, 21] # Fibonacci numbers

phi = (1 + sqrt(5)) / 2
phi2 = (1 - sqrt(5)) / 2

def fib_approx(n): return (phi**n - phi2**n) / sqrt(5)

x = range(len(data))
y = [fib_approx(n) for n in x]

# Now plot to compare fib_raw and y
# Compare error, etc

Trong trường hợp này, bản thân các giá trị của dãy Fibonacci không có liên quan. Tất cả những gì chúng tôi cần ở đây là kích thước của chuỗi đầu vào mà chúng tôi đang so sánh với.


Tôi mới sử dụng Python, ** làm gì trong trường hợp này? Tôi đã đọc về * args và ** kwargs, nhưng điều này có vẻ khác.
lukas_o

1
Luỹ thừa. phi với lũy thừa của n.
Mateen Ulhaq

0

Ví dụ rất đơn giản:

def loadById(self, id):
    if id in range(len(self.itemList)):
        self.load(self.itemList[id])

Tôi không thể nghĩ ra giải pháp nào không sử dụng thành phần range-len một cách nhanh chóng.

Nhưng có lẽ thay vào đó, điều này nên được thực hiện với try .. exceptđể giữ cho trăn trở lại, tôi đoán ..


1
if id < len(self.itemList) Nhưng try...excepttốt hơn, như bạn nói.
saulspatz

Điều này không tính đến id <0
IARI

0

Mã của tôi là:

s=["9"]*int(input())
for I in range(len(s)):
    while not set(s[I])<=set('01'):s[i]=input(i)
print(bin(sum([int(x,2)for x in s]))[2:])

Nó là một bộ cộng nhị phân nhưng tôi không nghĩ rằng phạm vi len hoặc bên trong có thể được thay thế để làm cho nó nhỏ hơn / tốt hơ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.