2016-04-06 9 views
0

これを行う方法はわかっていますが、私には非常にpythonicしていません。これを行うクリーナーの方法はありますか?反復しながらリストを編集する(pythonic way!)

(私はそれをしたい方法です)
arr = list(range(10)) 
print(arr) 
for n in range(len(arr)): 
    # Perform som operation on the element that changes the value "in place" 
    arr[n] += 1 
print(arr) 

出力:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

答えて

3

彼らは言いました。あなたが行うことができますリストを作成している間、あなたが操作を行いたい場合しかし:

arr = [u + 1 for u in range(10)] 

私がない限り、(あなたは、Python 2を使用している場合は、xrangerangeを変更するには、Python 3を使用していると推定しますリストのサイズは非常に小さい)、Python 2 range関数が実際にlistを返しますが、xrangeはイテレータを返します。 Python 3 range関数は、古いxrangeに似たイテレータを返します(ただし、いくつかの改良点があります)。

arrでは、新しいlistオブジェクトと現在のlistオブジェクトを交換することなく、変更する既存listであれば、あなたは

arr[:] = [u + 1 for u in arr] 

を行うことができます。ここarrを使用した場合の違いを示しているいくつかのコードがあります割り当ての左側にあるarr[:]

arr = list(range(10)) 
b = arr 
print(id(arr), id(b)) 
arr = [u + 1 for u in arr] 
print(id(arr), id(b)) 
print(arr, b) 

c = arr 
print(id(arr), id(c)) 
arr[:] = [u + 1 for u in arr] 
print(id(arr), id(c)) 
print(arr, c) 

出力

3073636268 3073636268 
3073629964 3073636268 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
3073629964 3073629964 
3073629964 3073629964 
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 

だからarr = [u + 1 for u in arr]は、新しいリストオブジェクトに名前arrを結合するが、arr[:] = [u + 1 for u in arr]は効果的に既存のリストオブジェクトを変異させます。 "Under the Hood"では、新しい一時的なリストオブジェクトを作成し、その内容を古いリストオブジェクトにコピーします。

+0

後者は効率的ですか? – Clausen

+0

@Clausen:実際には、 'arr = [uのarrのためのu + 1]'を実行するよりも少し遅いですが、リストが大きい場合を除いて速度の違いに気付かないでしょう。しかし、 'arr [:] ='を使用する主な利点は、 'arr'に対する複数の参照がある場合、Martijnが答えで説明するように、それらが有効であるということです。単に 'arr ='を使うと、他の参照は更新されたデータではなく古いデータになります。 –

+0

@Clausen:最新の回答をご覧ください。 –

5

あなたはlist comprehensionを使用することができます。

​​

これは新しいリストを生成します。上の例では、結果を同じ名前に戻します。

リストに複数の参照があり、インプレースで変更する必要がある場合(他の参照で変更が参照されるように)、IDスライス([:])に割り当てて、リバインドではなくリストのすべてのインデックスを更新します名前:

arr[:] = [i + 1 for i in arr] 

は、これが最初の新しいリストオブジェクトを作成し、Pythonは、両方のリストが同じ大きさであり、再び第二のリストを解放する前に、単に要素間でコピーすることを確認するために十分スマートです。

あなたも、余分なリストを作成しないように、その場合にはジェネレータ式を使用することができます。

arr[:] = (i + 1 for i in arr) 

これは、新しい要素のための余地を作るために脇にオリジナルの要素を移動しますが、新しいPythonのリストオブジェクトが作成されませんこのため。これは少しより多くのメモリを効率的にする必要があります。

+0

非常に非常にpythonic!私は実際にこれをマイクロpythonで実装しているので、私は新しいリストを作成したくないです(私のメモリにはすでに飽き飽きしています!)ので、おそらくインプレースの解決策に固執するでしょう。 – Clausen

+2

@Clausen:メモリ制約のあるenvs生成式を使用してください。 –

+2

@Clausen:複数の回答が見つかりましたのでうれしいです!残念ながら、ここで答えの一つに「受け入れられた」マークを与えることができます。あなたが最も役立ったと感じるものを選んでください(あなたが選ぶことができない場合は、まったく選ぶこともできません)。 –

3

使用リスト内包:

arr = [x + 1 for x in arr] 
関連する問題