2013-06-05 18 views
17

でminまたはmaxの値のインデックス検索:各タプルの最初の項目は範囲のリストである、と私はしたい私は、フォームの構造持っているPythonの

>>> items 
[([[0, 1], [2, 20]], 'zz', ''), ([[1, 3], [5, 29], [50, 500]], 'a', 'b')] 

を開始インデックスに基づいて昇順に範囲を提供するジェネレータを作成します。

範囲リストは既に開始インデックスによってソートされているので、この操作は簡単です。ソートされたマージだけです。私は良い計算効率でそれを行うことを望んでいるので、私は暗黙のうちに私のマージの状態を追跡する良い方法の1つは、その開始インデックスが最も小さいタプルのリストの先頭から範囲リスト。

min()を使用して、私が最初に望むのは[0, 1]ですが、どのようにインデックスを取得できますか?

私はこれを持っている:私は、その後min()何とか以上、それはリストの一回いずれも失敗することができ、各リストに私の最初の項目を与える空になり、またそれがどのようにはっきりしていない

[ min (items[i][0]) for i in range(len(items)) ] 

索引をpop()で使用するには、リスト内でバックアップを探す必要はありません。

要約すると:私のために返すジェネレータを構築したい:

([0,1], 'zz', '') 
([1,3], 'a', 'b') 
([2,20], 'zz', '') 
([5,29], 'a', 'b') 
([50,500], 'a', 'b') 

、あるいはより効率的に、私はこれだけのデータが必要になります。

[0, 1, 0, 1, 1] 

(私がしたいタプルのインデックス

+1

私は前の回答のために[ 'mergeiter'機能](http://stackoverflow.com/a/14465236)を書きました。 'enumerate()'でインデックスを追加します。 –

+0

@MartijnPieters Pythonでかなり緑色だったので、私は最初にあなたの 'mergeiter'関数をgrokkingしていました。しかし、これらの他の答えを見て、あなたのアプローチは明らかに正しいタイプです。しかし、それは答えとして投稿されていない唯一のものです... –

答えて

3

これは動作します:

by_index = ([sub_index, list_index] for list_index, list_item in 
      enumerate(items) for sub_index in list_item[0]) 
[item[1] for item in sorted(by_index)] 

は与える:

[0, 1, 0, 1, 1] 

詳細です。発電機:

by_index = ([sub_index, list_index] for list_index, list_item in 
      enumerate(items) for sub_index in list_item[0]) 
list(by_index)  
[[[0, 1], 0], [[2, 20], 0], [[1, 3], 1], [[5, 29], 1], [[50, 500], 1]] 

だから、必要な唯一のものは、唯一の希望、インデックスのソートとなっている:

[item[1] for item in sorted(by_index)] 
+0

私は、おそらくランタイムを恐ろしいものにすることはないが、ソートは完全に不要であると思う。分操作のみが必要です –

+0

Pythonの並べ替えは非常に効率的です(http://en.wikipedia.org/wiki/Timsort)。マージソートも使用されます。私があなたのことを正しく理解すれば、すべての指標に「分」を適用したいと考えています。最も小さいものを取り出し、リストが消費されるまで繰り返します。私は大きなリストの方がソートが速く、項目がすでにソートされている場合は、いくつかのテストを実行します。 –

+0

Hm。あなたは正しいかもしれない。結局のところ、1分以上の操作があります。 –

41
from operator import itemgetter 
index, element = max(enumerate(items), key=itemgetter(1)) 

の中で最も大きな要素のインデックスを返します。と要素そのもの。

+0

偉大な、私はいくつかの詳細をドリルダウンしたいと思う(最初のインデックスの一部でソートしたいと言うように)、私はそれのためのラムダ?なぜ私はそれほど複雑なものにしたいのかの理由として私の "役に立たないもの"を考慮してください:) –

+0

私は最後のコメントで私の質問に答えるでしょう、私は深く掘る方法はラムダと思う。 –

+0

'max(enumerate(items)、key = lambda x:x [1])'、インポートを保存します。 – ibrahim5253

0

あなたが内部の範囲リストは、あなたが

def min_idx(l, key=lambda x: x): 
    min_i, min_key = None, float('inf') 
    for i, v in enumerate(l): 
     key_v = key(v) 
     if key_v < min_key: 
      mini_i = i 
      min_key = key_v 
    return min_i 

def merge_items(items): 
    res = [] 
    while True: 
     i = min_idx(items, key=lambda i: i[0][0][0]) 
     item = items[i] 
     res.append((item[0][0],) + item[1:]) 
    return res 
しかし、最小値のインデックスを返す関数をしたいようですね

sorted(sum([ [(rng,) + i[1:] for rng in i[0]] for i in items ], []), lambda i: i[0][0]) 

にソートされているという事実を使用しようとしていない場合、それは簡単です

1

ので、これはあなたが探しているその効率的なバージョンを取得するための本当の迅速かつ簡単な方法です:ここで

a = [] 
count = 0 
for i in items: 
    for x in i[0]: 
     #place a list with the index next to it in list a for sorting 
     a.append((x,count)) 
#continually grabs the smallest list and returns the index it was in 
sort = [a.pop(a.index(min(a)))[1] for i in range(len(a))] 

は、それが機能することを示すために、あなたのアイテムである:

>>> items = [([[0, 1], [2, 20]], 'zz', ''), ([[1, 3], [5, 29], [50, 500]], 'a', 'b')] 
>>> a = [] 
>>> count = 0 
>>> for i in items: 
...  for x in i[0]: 
...    a.append((x,count)) 
...  count += 1 
... 
>>> sort = [a.pop(a.index(min(a)))[1] for i in range(len(a))] 
>>> sort 
[0, 1, 0, 1, 1] 
+0

私は再検索を避けようとしていました。これは、 'a.index(min(a))'がするものです。インデックスは検索です... –

+0

ああ、大丈夫です。そのリストの理解は、ほぼすべての配列のための迅速なソーターです!リスト、リストのリスト...それは基本的に何にでも作用します、私は '[1]'を追加する必要がありました。あなたがそれらを見たいと思わないなら、あなたがソートすることを計画する方法の周りに私の頭を包むのは難しいですが... –

+0

それは私も問題を投稿した理由は、あまりにもそれの周りに私の頭を包むのは難しいしかし、それを行う方法になる必要があります。計算効率を上げるために、各サブアレイをどれだけ下に移動したかの状態を追跡するだけです。それは私が思うようにそれらをポップすることによって行うことができますが、私はちょうどそれをすべて一緒に置く方法を知らない。あなたの説明に基づいて –

0

私は何が起こったのか分かりませんが、誰もがマークから少し離れていると思います。私は解決しようとしている問題を説明することに悪い仕事をすることにそれを責めます。とにかく、ここで私が得ているどのくらいです:

items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0) 

これは私が道のほとんどをかかりますが、どのように対処するために残って、1つのリストが使い果たされている状況を扱っています。一度それが世話をしたら、これをジェネレータにするのは自明でなければなりません。ループの中に入れて、内部に収めることができます。また、あまりにも多くの作業をせずに、ジェネレータを効率的に並べ替えることができます。

>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0) 
[0, 1] 
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0) 
[1, 3] 
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0) 
[2, 20] 
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in <lambda> 
IndexError: list index out of range 

更新:チケットである上minにまだ有効な-項目の適切なサブセットを組み立て

def next_value_in_sections(sections):     
    while 1:           
     idxs = []          
     for i, x in enumerate(sections):    
      if x[0]:         
       idxs.append(i)       
     print idxs          
     if not idxs:         
      break          
     j = min(idxs, key=lambda x: sections[x][0][0]) 
     yield (sections[j][0].pop(0), j)    

items = [([[0, 1], [2, 20]], 'zz', ''),    
     ([[1, 3], [5, 29], [50, 500]], 'a', 'b')]  
x = next_value_in_sections(items)      
for i in x:           
    print i           

が実行:私はまだこれを注意しましょう

$ python test.py 
[0, 1] 
([0, 1], 0) 
[0, 1] 
([1, 3], 1) 
[0, 1] 
([2, 20], 0) 
[1] 
([5, 29], 1) 
[1] 
([50, 500], 1) 
[] 

を向上させることができ、idxsリストには、各反復を再構築されています。それは必要ではありませんが、それを行うことで漸近的な境界が改善されるわけではありません...もちろん、実際にはパフォーマンスについて心配する必要があります。ラムダの使用が良いアイデアかどうか単純に狂気への降下である minを取り除くことなく、その周りの道を見てください。

+0

これは少し疲れているかもしれませんが、 'try'と' except'に入れて、 'except'の中でどのリストが空であるのかを把握し、残りの部分を持っているのをなぜ知っているのですか? –

+0

これを例外にすることはあまりにも重いと感じています。私はそれらを不要とみなすので、リストを並べ替えたり組み立てたりするのを避けることさえ考えています。入力リストとしてジェネレータとの互換性を保つつもりなら、例外が素晴らしいevemを再生できるように見えます。それはいいですね。私はそれのための解決策を得たと思う。一度テストしたら回答を編集します –

25

この方法は、任意のイテラブルの最大要素のインデックスを検索し、任意の外部の輸入を必要としない:

def argmax(iterable): 
    return max(enumerate(iterable), key=lambda x: x[1])[0] 
+2

1回のスイープでmaxとargmaxの両方を与えることができるノンループソリューションです! – gaborous

11

リストの最大のインデックス:

def argmax(lst): 
    return lst.index(max(lst)) 

がある場合最大値が重複していれば、最初に見つかった最大値のインデックスを返します。 ARGMAXを取得する

+4

また、リストを2回反復するので、これをしないでください。 – mrexodia

1

さらにもう1つの方法は、次のとおりです。

def argmax(lst): 
    return max(range(len(lst)), key=lst.__getitem__) 
関連する問題