range (len (a))가 필요합니까?


85

SO에 대한 파이썬 질문에서 이러한 유형의 표현을 자주 찾습니다. iterable의 모든 항목에 액세스하기 위해

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

어색한 글쓰기 방법입니다.

for e in a:
    print(e)

또는 iterable의 요소에 할당하는 경우 :

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

다음과 같아야합니다.

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]

또는 인덱스 필터링 :

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

다음과 같이 표현할 수 있습니다.

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

또는 목록의 내용이 아닌 길이 만 필요한 경우 :

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

다음 중 하나 일 수 있습니다.

for _ in a:
    doSomethingUnrelatedToA()

우리가 파이썬에서 enumerate, 슬라이스, filter, sorted, 파이썬 등 ...으로 for구조가 반복 가능 객체를 반복하기위한 것입니다 및뿐만 아니라 정수의 범위, 당신이 필요가 실제 사용 사례는 in range(len(a))?


5
나는 range(len(a))일반적으로 파이썬에 대해 상당히 경험이없는 사람들 이라고 생각한다 (일반적으로 프로그래밍에 반드시 필요한 것은 아니지만).
rlms

range(len(a))파이썬을 배울 때만 사용했습니다 . 요즘에는 말씀하신대로 교체하기가 매우 쉽기 때문에 그렇지 않습니다.

별로. range(len(a))목록 a의 내용이 필요하지 않고 길이 만 필요하기 때문에 자주 사용 합니다.
aIKid

8
루프에서 현재 요소 이전과 이후에 요소에 액세스해야하는 경우 어떻게됩니까? 나는 보통 그것을 for i in range(len(a)): doSomethingAbout(a[i+1] - a[i])우회하는 방법이 있습니까?
Zhang18

1
@ JaakkoSeppälä가 동의했습니다. 나는 단지 값이 아닌 인덱스를 반복해야하는 주요 문제를 설명하기 위해 예제를 제공하고 있으며, 끝 부분에 요점 외에 코너 케이스가 있음을 이해했습니다.
Zhang18

답변:


17

시퀀스의 인덱스로 작업해야하는 경우 예-사용합니다 ... 예를 들어 numpy.argsort에 해당하는 경우 ... :

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

좋아, 이건 현명 해 보인다. 대단히 감사합니다. 그러나 문제는 새로 정렬 된 인덱스 목록으로 무엇을 할 것인가입니다. 이 목록을 통해 반복 가능한 항목에 다시 액세스하면 개가 자신의 꼬리를 물게됩니다.
Hyperboreus 2013 년

1
동일합니다 : [ix for ix, _ in sorted(enumerate(a), key=lambda i: i[1])]비록 당신의 것이 더 멋지고 괴짜이지만.
Erik Kaplun 2013 년

10

목록의 두 요소에 동시에 액세스해야하는 경우 어떻게해야합니까?

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

이것을 사용할 수는 있지만 명확하지 않을 수 있습니다.

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

개인적으로 나도 100 % 만족하지 않습니다!


1
for ix, i in enumerate(a)동등한 것 같지 않습니까?
Erik Kaplun

2
대신 pairwise 를 사용해야 합니다.
플라잉 양

그런 상황에서 나는 :for a1,a2 in zip(a[:-1],a[1:])
Luca Amerio

7

짧은 대답 : 수학적으로 말하면 아니오, 실제적인 측면에서 예, 예를 들어 의도적 프로그래밍의 경우.

기술적으로 대답은 다른 구조를 사용하여 표현할 수 있기 때문에 "아니요, 필요하지 않습니다" 입니다. 그러나 실제로는 for i in range(len(a)(또는 for _ in range(len(a))인덱스가 필요하지 않은 경우) 시퀀스의 항목을 아무것도 사용할 필요없이 시퀀스에 항목이있는만큼 반복하고 싶다는 것을 명시 적으로 사용합니다.

그래서 : "필요가 있습니까?" ? — 예, 가독성을 위해 코드의 의미 / 의도를 표현하는 데 필요 합니다.

참조 : https://en.wikipedia.org/wiki/Intentional_programming

그리고 분명히 반복과 관련된 컬렉션이 전혀없는 경우에 for ... in range(len(N))의지하지 않는 유일한 옵션입니다.i = 0; while i < N; i += 1 ...


어떤 장점이 for _ in range(len(a))이상 for _ in a?
Hyperboreus 2013 년

@Hyperboreus : 예, 귀하의 의견이 나오기 몇 초 전에 제 답변을 수정했습니다 ... 그래서 차이점은 "모든 항목에 대해 a"가 아니라 "에 항목이 있으므로 여러 번 반복 하여 " ... 의 내용에 관계없이의 요소aa 는 의도적 프로그래밍 뉘앙스입니다.
Erik Kaplun 2013 년

귀하의 모범에 감사드립니다. 내 질문에 포함 시켰습니다.
Hyperboreus 2013 년

2
목록에 'hello'있는만큼의 항목 이있는 목록을 얻으려면 다음 a을 사용하십시오.b = ['hello'] * len(a)
steabert

2

의견뿐만 아니라 개인적인 경험으로 가고, 나는 더 없다, 더 말할 필요 에 대한이 range(len(a)). 할 수있는 모든 range(len(a))작업은 다른 방식 (일반적으로 훨씬 더 효율적)으로 수행 할 수 있습니다.

게시물에 많은 예를 주셨으므로 여기서 반복하지 않겠습니다. 대신 " a항목이 아닌의 길이 만 원하면 어떨까요?" 라고 말하는 사람들을 위해 예를 들어 보겠습니다 . 이것은 사용을 고려할 수있는 유일한 경우 중 하나입니다 range(len(a)). 그러나 이것도 다음과 같이 할 수 있습니다.

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

Clements 답변 (Allik에 의해 표시됨)을 다시 작업하여 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]
>>>

따라서 결론적으로 range(len(a))필요 하지 않습니다 . 유일한 장점은 가독성입니다 (의도는 분명합니다). 그러나 그것은 단지 선호도와 코드 스타일 일뿐입니다.


대단히 감사합니다. 그리고 다시, 가독성은 (부분적으로) 보는 사람의 눈에 달려 있습니다. 나는 for _ in a:"반복하지만 그 내용은 무시한다"로 해석하지만 for _ in range(len(a))"a의 길이를 얻은 다음 같은 길이의 정수를 여러 개 생성 한 다음 마지막으로 내용을 무시한다"로 해석 합니다.
Hyperboreus 2013 년

1
@Hyperboreus-매우 사실입니다. 코드 스타일 일뿐입니다. 내 목표는 "사용 range(len(a))하지 않으면이 작업을 수행 할 수 없습니다"시나리오 가 절대 없을 것임을 보여주는 것이 었습니다 .

참고 : 예를 들어 erlang에서 단일 밑줄은 익명 변수입니다. erlang은 파괴적인 할당을 허용하지 않기 때문에 다른 변수와 달리 재 할당 (또는 "일치") 할 수있는 유일한 변수입니다. 고문당한 유리로 지어진 그의 궁전 벽 뒤에서 기다립니다.)
Hyperboreus 2013 년

2

때때로하기 matplotlib 필요 range(len(y))하지만, 예를 들어, y=array([1,2,5,6]), plot(y), 잘 작동 scatter(y)하지 않습니다. 하나는 써야한다 scatter(range(len(y)),y). (개인적으로, 나는 이것이 버그라고 생각 scatter, plot그 친구 scatterstem가능한 한 같은 호출 시퀀스를 사용해야합니다.)


2

어떤 종류의 조작을 위해 인덱스를 사용해야 할 때 현재 요소가 충분하지 않을 때 있으면 좋습니다. 예를 들어 배열에 저장된 이진 트리를 생각해보십시오. 각 노드의 직계 자식을 포함하는 튜플 목록을 반환하도록 요청하는 메서드가있는 경우 인덱스가 필요합니다.

#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

물론 작업중인 요소가 객체 인 경우 get children 메서드를 호출 할 수 있습니다. 그러나 예, 일종의 조작을 수행하는 경우에만 인덱스가 필요합니다.


1

귀하의 예제 중 어느 것도 다루지 않는다고 생각하는 사용 사례가 있습니다.

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

나는 더 우아한 접근 방식을 배우는 것이 너무 행복하지만 파이썬에 비교적 익숙하지 않습니다.


4
나의 무지. 2 개의 목록을 병렬로 반복하는 훨씬 더 파이썬적인 방법 인 zip이 있습니다.
Jim

1
헉, 내가 정말 유사한 사용 사례 여기 온 ... [a - b for a, b in zip(list1, list2)]보다는 훨씬 좋네요 [list1[i] - list2[i] for i in range(len(list1))].. 감사합니다!
kevlarr

1

len(a)객체 의 첫 번째 항목 b(보다 큼 a) 을 반복해야하는 경우 다음을 사용해야합니다 range(len(a)).

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

2
이것은 더 명확 할 수 있습니다.for b_elem in b[:len(a)]:...
aquirdturtle

@aquirdturtle 아마도 더 명확 할 수도 있지만 솔루션은 b & a가 크면 비용이 많이들 수있는 새 목록을 생성합니다.
PM 2Ring dec

itertools.islice대신 사용하여 처리해야합니다 .
MisterMiyagi

1

때로는 컬렉션 자체에 관심이 없습니다 . 예를 들어, 원시 데이터와 "근사치"를 비교하기 위해 간단한 모델 적합 선을 생성합니다.

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

이 경우 피보나치 수열 자체의 값은 관련이 없습니다. 여기에 필요한 것은 비교하려는 입력 시퀀스의 크기뿐이었습니다.


저는 Python을 처음 사용합니다.이 경우 **는 무엇을합니까? 나는 * args와 ** kwargs에 대해 읽었지만 이것은 다르게 보인다.
lukas_o

1
지수화. 파이 n의 거듭 제곱으로.
Mateen Ulhaq

0

아주 간단한 예 :

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

레인지 렌즈 구성을 빨리 사용하지 않는 솔루션은 생각할 수 없습니다.

하지만 아마 대신에 try .. except비단뱀을 유지하기 위해 해야 할 것 같아요 ..


1
if id < len(self.itemList) 그러나 try...except당신이 말했듯이 더 좋습니다.
saulspatz

이것은 id <0을 설명하지 않습니다.
IARI

0

내 코드는 다음과 같습니다.

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

이진 가산기이지만 범위 len 또는 내부를 더 작게 / 더 좋게 만들기 위해 바꿀 수 있다고 생각하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.