2016-09-01 11 views
4

リストをPythonで分類する最良の方法は何ですか?例えばPythonのリストを分類する

totalist is below 

totalist[1] = ['A','B','C','D','E'] 
totalist[2] = ['A','B','X','Y','Z'] 
totalist[3] = ['A','F','T','U','V'] 
totalist[4] = ['A','F','M','N','O'] 

は、私は最初の2つの項目が['A','B']、基本的にlist[1]list[2]あるリストを取得したいとします。一度に1つのアイテムを反復することなくこれらを取得する簡単な方法はありますか?このようなもの?

if ['A','B'] in totalist 

私はそれが動作しないことを知っています。

+3

コードは、あなたが何をしようとしたのですか? –

+1

答えを示唆しているように、何らかの形で反復せずにこれを解決する方法はありません。これを効率的にチェックすることが大きな優先事項である場合は、データの表現方法をリメイクする必要があります。スピードを改善するためにいくらかの空間複雑性を犠牲にする。たとえば、リストを作成するときに、どの行がプロパティを満たすかをメモすることができます。 – gowrath

答えて

3

各リストの最初の2つの要素を確認できます。

for totalist in all_lists: 
    if totalist[:2] == ['A', 'B']: 
     # Do something. 

注: Kasramvdによって提案されたワンライナーソリューションはあまりにも非常にいいです。私は自分のソリューションをより読みやすくしました。私は、理解は通常のforループよりもわずかに速いと言いますが。 (私は自分自身をテストしました)

+0

これはすごくうまくいくはずです、どうしてdownvoteがあるのか​​分かりませんが、私はそれを打ち消しました。 – bravosierra99

+0

@ bravosierra99ありがとう、あなたは、要素を反復する必要はありませんがある場合、OPは解決策を求め、おそらく私はdownvoteを持っている理由です。しかし、私はすべてのリストをループすることなくこれを達成できる方法は見当たりません。 – Rockybilly

+0

私は彼がすべてのリストのすべての個々のアイテムをループすることなく意味すると思います。あなたはリストを繰り返すか、それぞれをチェックすることはできません.... – bravosierra99

1

基本的には、これを入れ子リストでPythonで行うことはできません。しかし、あなたはここに最適化されたアプローチを探している場合は、いくつかの方法があります:あなたがインデックスをしたい場合

>>> [sub for sub in totalist if sub[:2] == ['A', 'B']] 
[['A', 'B', 'C', 'D', 'E'], ['A', 'B', 'X', 'Y', 'Z']] 

はサブリストの最初の2つの項目を意図したリストを比較することで、簡単なリスト内包を使ってenumerateを使用します。

>>> [ind for ind, sub in enumerate(totalist) if sub[:2] == ['A', 'B']] 
[0, 1] 

そして、ここでは、大規模なデータセットを処理しているとき、かなり最適化されてnumpyのでアプローチです:

>>> import numpy as np  
>>> 
>>> totalist = np.array([['A','B','C','D','E'], 
...      ['A','B','X','Y','Z'], 
...      ['A','F','T','U','V'], 
...      ['A','F','M','N','O']]) 

>>> totalist[(totalist[:,:2]==['A', 'B']).all(axis=1)] 
array([['A', 'B', 'C', 'D', 'E'], 
     ['A', 'B', 'X', 'Y', 'Z']], 
     dtype='|S1') 

また、あなたは、あなたが機能的な方法を探しているループを使用しない場合のpythonでの理解を一覧表示する代わりに、リスト内包として最適化されていないようfilter機能、使用することができます。

>>> list(filter(lambda x: x[:2]==['A', 'B'], totalist)) 
[['A', 'B', 'C', 'D', 'E'], ['A', 'B', 'X', 'Y', 'Z']] 
+0

FYI、' filter'は完全に最適化されていますあなたの述語関数はC_で実装された組み込み関数です(入力が十分です)。その場合、通常は同等のgenexpr/listcompsより速く実行されます。 genexpr/listcompがインラインにできる 'lambda 'が必要な場合、それは間違いなく遅くなります。また、genexpr/listcompで回避できない' def'関数を使用している場合、通常はパフォーマンスが似ています、しかしちょうど)。 'filter'は進歩しており、genexpr/listcompだけを使うのはまったくいいですが、理解していればスピードアップに使うことができます。 – ShadowRanger

+0

@ShadowRangerええ、私はそれを知っていますが、コメントをいただきありがとうございます。 – Kasramvd

1

これは可能です。

>>> for i in totalist: 
...  if ['A','B']==i[:2]: 
...    print i 
+0

私は答えを書いて、同じことを書いていたのを見ました。 :-) –

+0

私たちすべてに起こります! –

0

あなたは、パフォーマンス(コスト)を心配することを意味します。これを行う必要がある場合や、パフォーマンスが心配な場合は、別のデータ構造が必要です。これにより、リストを作成するときに少しコストがかかりますが、フィルタリングするときに時間を節約できます。

最初の2つの要素に基づいてフィルタを適用する必要がある場合(最初のn要素には一般化されません)、リストが作成されたときに、そのキーがタプル最初の2つの要素のうち、項目はリストのリストです。

次に、dictルックアップを実行するだけでリストを取得できます。これは簡単で、リストを作成する際にメモリや時間をほとんどかけることなく、スピードアップを可能にします。

+0

これは常に最初の2つの要素ではありませんが、リストを通過するにつれて増加し続けます。基本的には、リストはパスであり、ツリーごとに一種のパスを分類します。上記のif文を使用します。 – user1179317

2

楽しみのためだけに、C層に要素ごとの作業をプッシュするitertoolsソリューション:

from future_builtins import map # Py2 only; not needed on Py3 
from itertools import compress 
from operator import itemgetter 

# Generator 
prefixes = map(itemgetter(slice(2)), totalist) 
selectors = map(['A','B'].__eq__, prefixes) 

# If you need them one at a time, just skip list wrapping and iterate 
# compress output directly 
matches = list(compress(totalist, selectors)) 

これは、すべて1つのライニングが考えられます。

matches = list(compress(totalist, map(['A','B'].__eq__, map(itemgetter(slice(2)), totalist)))) 

が、私はお勧めしませんそれ。 totalistは発電機ではなく、再反復可能シーケンスであるかもしれない場合なお、あなたが追加し、それを倍にitertools.teeを使用したいと思います:

totalist, forselection = itertools.tee(totalist, 2) 

forselectionmapprefixesの定義を変更、ないtotalistcompressは両方のイテレータを並列に反復するため、teeは意味のあるメモリオーバーヘッドを持ちません。

もちろん、他の人が指摘しているように、Cに移動しても、これは線形アルゴリズムです。理想的には、collections.defaultdict(list)のように、各listの2つの要素プレフィックス(tupleに変換され、法的にはdictに変換されます)からlistlistにそのプレフィクスを使用してマップするのが理想的です。次に、N listを線形検索する代わりに、一致する接頭辞を持つものを見つけるために、totaldict['A', 'B']を実行するだけで、結果はO(1)で取得されます(固定されていない作業でも一定スライスなし)。

例事前計算の作業:

from collections import defaultdict 

totaldict = defaultdict(list) 
for x in totalist: 
    totaldict[tuple(x[:2])].append(x) 

# Optionally, to prevent autovivification later: 
totaldict = dict(totaldict) 

次に、あなただけの持つ2つの要素の接頭辞のために効果的に瞬時にmatchesを取得することができます:

matches = totaldict['A', 'B'] 
+1

本当に楽しい!あなたは楽しい要素のための投票を得るが、これが受け入れられた答えであるようにしないでください! :) –

+0

@RolfofSaxony::-)私はitertools'が好きです。それはここでは当然適切ではありませんが、一般的なパターンは実際には他の目的のためにそれをうまく使用する方法のまともな例です。 OPのケースでは、私は 'defaultdict(list)'ルートに行くことをほぼ確実にしています。 – ShadowRanger

+0

@RolfofSaxonyいくつかの関数を組み合わせて楽しくする必要はありません。不必要な操作を行うのは正しい方法ではありません。特に、よりシンプルで高速なアプローチで行うことができる簡単な作業です。 – Kasramvd

関連する問題