web-dev-qa-db-ja.com

range(len(a))が必要ですか?

SOのpython質問でこのタイプの式を頻繁に見つけます。 iterableのすべてのアイテムにアクセスするためのいずれか

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

これは面倒な書き方です:

for e in a:
    print(e)

または、イテラブルの要素に割り当てる場合:

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

pythonにはenumerate、スライス、filtersortedなどがあります... As python forコンストラクトは、整数の範囲だけでなく反復可能なものを反復することを目的としています。in range(len(a))が必要な実際のユースケースはありますか

59
Hyperboreus

シーケンスのインデックスを操作する必要がある場合は、はい-使用します... numpy.argsort ...と同等の場合:

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

短い答え:数学的に言えば、いいえ、実用的な用語では、はい、たとえば、意図的なプログラミングの場合。

技術的には、数学的に正しい答えは"いいえ、必要ありません"であると思います。他の構成要素を使用して表現できるためです。とにかくすべてを表現できるので、どの構文/パラダイム構造を持っているかは本当に重要です。

しかし実際には、for i in range(len(a)またはインデックスが必要ない場合はfor _ in range(len(a)))を使用して、シーケンス内のアイテムを何でも使用せずにシーケンス内のアイテムと同じ回数だけ繰り返したいことを明示します。

「必要はありますか?」の部分に答えるために-Ineedコードの意味/意図を表現する読みやすさの目的。

参照: https://en.wikipedia.org/wiki/Intentional_programming

_(P.S.同時に、以下はIntentional Programmingの観点から意味的に同等であるようです:

for _ in a:
    ...

または

b = ["hello" for _ in a]

...全体として、違いは、"aにアイテムがあるのでAS MANY TIMESを繰り返します。"とは対照的に、"aのすべての要素に対して、 a "...の内容は、最終的には意図的なプログラミングのニュアンスです。

6
Erik Allik

リストの2つの要素に同時にアクセスする必要がある場合はどうなりますか?

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%満足していません!

6
Giswok

私はあなたの例のどれもカバーしていないと思うユースケースを持っています。

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

私はpythonに比較的新しいのですが、よりエレガントなアプローチを学ぶことができてとても幸せです。

2
Jim

Matplotlibにはrange(len(y))が必要な場合があります。たとえば、y=array([1,2,5,6])plot(y)は正常に機能し、scatter(y)は不要です。 scatter(range(len(y)),y)と書く必要があります。 (個人的には、これはscatterのバグだと思います; plotとその友達scatterstemは可能な限り同じ呼び出しシーケンスを使用する必要があります。)

2

コメントだけでなく、個人的な経験から言えば、私はノーと言います。range(len(a))にはneedはありません。 range(len(a))でできることはすべて、別の(通常ははるかに効率的な)方法で実行できます。

あなたはあなたの投稿で多くの例を挙げたので、ここではそれらを繰り返しません。代わりに、「アイテムではなくaの長さだけが必要な場合はどうすればいいですか?」という例を挙げます。これは、range(len(a))の使用を検討する唯一の時間の1つです。ただし、これでも次のように実行できます。

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

クレメンツの回答(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))必要ではありません。唯一の利点は可読性です(その意図は明確です)。しかし、それは単なる好みとコードスタイルです。

2
iCodez

何らかの操作のためにインデックスを使用する必要があり、現在の要素が十分ではない場合に便利です。たとえば、配列に格納されているバイナリツリーを考えてみましょう。各ノードの直接の子を含むタプルのリストを返すように要求するメソッドがある場合、インデックスが必要です。

#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メソッドを呼び出すだけです。ただし、何らかの操作を行う場合にのみ、本当にインデックスが必要です。

2
CleoR

時々、あなたは本当にコレクション自体を気にしない。たとえば、「近似」と生データを比較するための単純なモデル適合線を作成します。

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

この場合、フィボナッチ数列自体の値は無関係です。ここで必要なのは、比較する入力シーケンスのサイズだけです。

1
Mateen Ulhaq

私のコードは:

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または内部を置き換えて、より小さく/より良くすることはできないと思います。

0

オブジェクトbaよりも大きい)の最初のlen(a)アイテムを反復処理する必要がある場合は、おそらくrange(len(a))を使用する必要があります。

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

非常に簡単な例:

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

レンジレンズ構成をすぐに使用しない解決策は考えられません。

しかし、おそらく代わりに、これはtry .. exceptで実行してPythonicのままにする必要があると思います。

0
IARI