code

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

codestyles 2020. 12. 2. 21:23
반응형

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


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


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

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

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

기술적으로는 수학적으로 정답이 "아니요, 필요하지 않습니다"라고 생각합니다. 다른 구문을 사용하여 표현할 수 있기 때문입니다. 즉, 다른 구문과 동일합니다. 언어가 튜링이 완성 된 경우 어떤 구문인지는 실제로 중요하지 않습니다. / 패러다임 구조는 모든 것이 어차피 표현 될 수 있기 때문입니다.

그러나 실제로는 for i in range(len(a)(또는 for _ in range(len(a))인덱스가 필요하지 않은 경우) 시퀀스에있는 항목을 아무것도 사용할 필요없이 시퀀스에있는 항목 수만큼 반복하고 싶다는 것을 명시하기 위해 사용합니다 (또는 인덱스가 필요하지 않은 경우).

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

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

추신 이지만 동시에 의도적 프로그래밍 관점 에서 다음은 의미 상 동등하게 보입니다 .

for _ in a:
    ...

또는

b = ["hello" for _ in a]

... 모두 모두, 내가 차이는 당신이 정말 명시 할 것인지 여부 것 같다 "항목이 있기 때문에 여러 번 반복 a" 반대 "의 모든 요소가 a관계의 내용, a" ... 그래서 결국 의도적 인 프로그래밍 뉘앙스입니다.


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

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 % 만족하지 않습니다!


의견뿐만 아니라 개인적인 경험으로 가고, 나는 더 없다, 더 말할 필요 에 대한이 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]
>>>

So, in conclusion, range(len(a)) is not needed. Its only upside is readability (its intention is clear). But that is just preference and code style.


Sometimes matplotlib requires range(len(y)), e.g., while y=array([1,2,5,6]), plot(y) works fine, scatter(y) does not. One has to write scatter(range(len(y)),y). (Personally, I think this is a bug in scatter; plot and its friends scatter and stem should use the same calling sequences as much as possible.)


I have an use case I don't believe any of your examples cover.

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

I'm relatively new to python though so happy to learn a more elegant approach.


It's nice to have when you need to use the index for some kind of manipulation and having the current element doesn't suffice. Take for instance a binary tree that's stored in an array. If you have a method that asks you to return a list of tuples that contains each nodes direct children then you need the index.

#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

Of course if the element you're working on is an object, you can just call a get children method. But yea, you only really need the index if you're doing some sort of manipulation.


Sometimes, you really don't care about the collection itself. For instance, creating a simple model fit line to compare an "approximation" with the raw data:

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

In this case, the values of the Fibonacci sequence itself were irrelevant. All we needed here was the size of the input sequence we were comparing with.


Very simple example:

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

I can't think of a solution that does not use the range-len composition quickly.

But probably instead this should be done with try .. except to stay pythonic i guess..


If you have to iterate over the first len(a) items of an object b (that is larger than a), you should probably use range(len(a)):

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

My code is:

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

It is a binary adder but I don't think the range len or the inside can be replaced to make it smaller/better.

참고URL : https://stackoverflow.com/questions/19184335/is-there-a-need-for-rangelena

반응형