インデックスを知っているリストの複数の要素にアクセスする


232

それらのインデックスを知って、与えられたリストからいくつかの要素を選択する必要があります。与えられたリスト[-2、1、5、3、8、5、6]からインデックス1、2、5の要素を含む新しいリストを作成したいとします。私がしたことは:

a = [-2,1,5,3,8,5,6]
b = [1,2,5]
c = [ a[i] for i in b]

それを行うためのより良い方法はありますか?c = a [b]のようなものですか?


1
ところで、私はここで別の解決策を見つけました。まだテストしていませんが、code.activestate.com / recipes /…に
tran

これは質問で述べたのと同じ解決策ですが、lambda関数にラップされています。
ウィルデリハム2017年

回答:


218

使用できますoperator.itemgetter

from operator import itemgetter 
a = [-2, 1, 5, 3, 8, 5, 6]
b = [1, 2, 5]
print(itemgetter(*b)(a))
# Result:
(1, 5, 5)

またはnumpyを使用できます:

import numpy as np
a = np.array([-2, 1, 5, 3, 8, 5, 6])
b = [1, 2, 5]
print(list(a[b]))
# Result:
[1, 5, 5]

しかし、実際には、現在のソリューションは問題ありません。それはおそらくそれらすべての中で最も控えめなものです。


35
+1で問題ないことを言及しc = [a[i] for i in b]ます。itemgetterbの要素が2つ未満の場合、解は同じことを行わないことに注意してください。
flornquake 2013

サイド :使用itemgetterをマルチプロセスにはない仕事に取り組んでいます。Numpyはマルチプロセスでうまく機能します。
Lior Magen

3
追加のコメント、a[b]作品のみときaですnumpyの配列は、あなたがnumpyの機能とそれを作成しますすなわち。
Ludwig Zhou

私は非numpyオプションをベンチマークしましたが、Python 3.44を使用してかっこ内に目的のインデックスを入力するよりもわずかに速く、itemgetterが最速であるように見えます
ragardner

@ citizen2077、記述した構文の例を挙げていただけますか?
alancalvitti

47

代替案:

>>> map(a.__getitem__, b)
[1, 5, 5]

>>> import operator
>>> operator.itemgetter(*b)(a)
(1, 5, 5)

最初のbuild-in関数は関数を使用するので便利です
silgon

最初の問題の問題は、__getitem__たとえばアイテムのタイプをマップする方法など、互換性がないように見えることですか?map(type(a.__getitem__), b)
alancalvitti

@alancalvitti 、lambda x: type(a.__getitem__(x)), b. この場合、使用しては、[..]よりコンパクトである:lambda x: type(a[x]), b
falsetru

9

別の解決策はパンダシリーズを経由することができます:

import pandas as pd

a = pd.Series([-2, 1, 5, 3, 8, 5, 6])
b = [1, 2, 5]
c = a[b]

その後、必要に応じてcをリストに戻すことができます。

c = list(c)

7

提供された5つの回答の実行時間を比較する、それほど広範囲ではない基本的なテスト:

def numpyIndexValues(a, b):
    na = np.array(a)
    nb = np.array(b)
    out = list(na[nb])
    return out

def mapIndexValues(a, b):
    out = map(a.__getitem__, b)
    return list(out)

def getIndexValues(a, b):
    out = operator.itemgetter(*b)(a)
    return out

def pythonLoopOverlap(a, b):
    c = [ a[i] for i in b]
    return c

multipleListItemValues = lambda searchList, ind: [searchList[i] for i in ind]

次の入力を使用します。

a = range(0, 10000000)
b = range(500, 500000)

単純なpythonループはラムダ操作が1秒近くで最も速く、リストをnumpy配列に変換した後、mapIndexValuesとgetIndexValuesはnumpyメソッドと一貫してかなり遅くなりました。データが既にnumpy配列にある場合、numpy.array変換を削除したnumpyIndexValuesメソッドは最速。

numpyIndexValues -> time:1.38940598 (when converted the lists to numpy arrays)
numpyIndexValues -> time:0.0193445 (using numpy array instead of python list as input, and conversion code removed)
mapIndexValues -> time:0.06477512099999999
getIndexValues -> time:0.06391049500000001
multipleListItemValues -> time:0.043773591
pythonLoopOverlap -> time:0.043021754999999995

どのPythonインタープリターを使用しているかはわかりませんが、最初の方法numpyIndexValuesはタイプなのでa、機能しません。私はあなたが変換するためにメンターことを推測しています、に最初の?brangeabnumpy.ndarrays
strpeter 2015年

@strpeterはい、私はリンゴとリンゴを比較していませんでした。numpyIndexValuesのテストケースの入力としてnumpy配列を作成しました。これを修正し、すべて同じリストを入力として使用します。
Don Smythe、2015年

4

私はこれがすでに考慮されていると確信しています:bのインデックスの量が小さくて一定である場合、次のような結果を書くことができます:

c = [a[b[0]]] + [a[b[1]]] + [a[b[2]]]

または、インデックス自体が定数の場合はさらに簡単になります...

c = [a[1]] + [a[2]] + [a[5]]

または、連続した範囲のインデックスがある場合...

c = a[1:3] + [a[5]]

思い出していただきありがとうございます[a] + [b] = [a, b]
onewhaleid


1

私の答えはnumpyまたはpythonコレクションを使用していません。

要素を見つける簡単な方法は次のとおりです。

a = [-2, 1, 5, 3, 8, 5, 6]
b = [1, 2, 5]
c = [i for i in a if i in b]

欠点:この方法は、大きなリストでは機能しない場合があります。リストが大きい場合は、numpyの使用をお勧めします。


5
繰り返す必要はありませんa[a[i] for i in b]
falsetru

1
この方法は、他の場合には機能しません。aさらに5つあった場合はどうなりますか?
TerryA


bがありますサイズを超える数字を持っている場合は、IndexErrors心配している場合は、してみてください[a[i] if i<len(a) else None for i in b]
576iの

0

静的インデックスと小さなリスト?

例のように、リストが小さく、インデックスが変更されない場合は、シーケンスのアンパッキングを使用するのが最善の場合があることを忘れないでください。

_,a1,a2,_,_,a3,_ = a

パフォーマンスが大幅に向上し、1行のコードを保存することもできます。

 %timeit _,a1,b1,_,_,c1,_ = a
10000000 loops, best of 3: 154 ns per loop 
%timeit itemgetter(*b)(a)
1000000 loops, best of 3: 753 ns per loop
 %timeit [ a[i] for i in b]
1000000 loops, best of 3: 777 ns per loop
 %timeit map(a.__getitem__, b)
1000000 loops, best of 3: 1.42 µs per loop

0

Python的な方法の種類:

c = [x for x in a if a.index(x) in b]

2
これはOPの例よりも「Python的」ではないと思います。コードの長さをほぼ2倍にしながらO(n)O(n^2)ソリューションをソリューションに変えることができました。リストにオブジェクトが含まれている場合、アプローチが失敗することにも注意してください。たとえば、aが含まれている場合float('nan')、これにより常にが発生しValueErrorます。
ブライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.