range(len(a))の必要はありますか?


85

SOに関するPythonの質問で、このタイプの式が頻繁に見つかります。反復可能なすべてのアイテムにアクセスするためのいずれか

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、Pythonの等...としてfor構築物は反復可能オブジェクトを反復するために意図されているだけでなくは整数の範囲を、あなたが必要があり、現実世界のユースケースはin range(len(a))


5
range(len(a))は通常、Pythonにかなり不慣れな人だと思います(ただし、必ずしも一般的なプログラミングに慣れているとは限りません)。
rlms 2013年

range(len(a))はPythonを学んでいたときにだけ使用しました。あなたが言ったように、今日では、私はそうしません。

あんまり。range(len(a))リストaの内容は必要なく、長さだけが必要なので、よく使用します。
aIKid 2013年

8
ループ内で、現在の要素の前後の要素にアクセスする必要がある場合はどうなりますか?私は通常それをfor i in range(len(a)): doSomethingAbout(a[i+1] - a[i])回避する方法を持っていますか?
zhang18 2017年

1
@JaakkoSeppäläは同意しました。値だけでなく、インデックスをループする必要があるという主な問題を説明するための例を示しただけで、最後に要点以外のコーナーケースがあることを理解しています。
zhang 1818年

回答:


17

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

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

OK、これは賢明に見えます。どうもありがとうございました。しかし、問題は、新しくソートされたインデックスのリストをどうするかということです。このリストを介して繰り返しアクセスできる場合、犬は自分の尻尾を噛みます。
Hyperboreus 2013年

1
と同等[ix for ix, _ in sorted(enumerate(a), key=lambda i: i[1])]です:しかし、あなたのものは間違いなくより良い/ geekierですが。
Erik Kaplun 2013年

10

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


1
for ix, i in enumerate(a)同等のようですよね?
Erik Kaplun 2018

2
代わりにペアワイズを使用する必要があります。
空飛ぶ羊

私は、これらの状況では:for a1,a2 in zip(a[:-1],a[1:])
ルカ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'と同じ数のアイテムを含むリストを取得するには、ab = ['hello'] * len(a)
steabert 2015年

2

コメントと個人的な経験で行くと、私はノーと言います、ありません 必要性のためにrange(len(a))。あなたができることすべてrange(len(a))、別の(通常ははるかに効率的な)方法で行うことができます。

あなたはあなたの投稿で多くの例を挙げたので、ここではそれらを繰り返しません。代わりに、「長さだけが必要な場合はどうすればよいですか?a「アイテムはなく、ですか?」ます。これは、の使用を検討できる唯一の時間の1つです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)ます。(個人的に、私はこれはバグだと思うscatterplotそしてその友人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

もちろん、作業中の要素がオブジェクトの場合は、getchildrenメソッドを呼び出すだけです。しかし、そうです、ある種の操作をしている場合にのみ、インデックスが本当に必要になります。


1

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

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

私はPythonに比較的慣れていませんが、よりエレガントなアプローチを学ぶことができてとてもうれしいです。


4
私の無知。zipがあります。これは、2つのリストを並行して反復するはるかにPython的な方法です。
ジム

1
ああ、私は本当に似たユースケースでここに来ました...[a - b for a, b in zip(list1, list2)]よりもずっといい[list1[i] - list2[i] for i in range(len(list1))]です..ありがとう!
kevlarr 2017

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

@aquirdturtleおそらくそれはより明確ですが、あなたのソリューションは新しいリストを作成します。これは、b&aが大きい場合はコストがかかる可能性があります。
PM2Ring19年

これは、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 2018年

0

非常に簡単な例:

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

range-lenコンポジションをすぐに使用しないソリューションは考えられません。

しかし、おそらく代わりに、これはtry .. except私が推測するpythonicを維持するために行う必要があります。


1
if id < len(self.itemList) しかしtry...except、あなたが言うように、より良いです。
saulspatz 2015

これは、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.