2017-09-26 12 views
1

(x、y)ペアのリストの辞書では、Python 3で最大のxを見つけるのに最も効率的な方法は何ですか?それらの値が異なる(x、y)のペアであっても辞書の最大yXYタプルのリストの辞書から最大のXとYを得る最も効率的な方法

roi = { '26580.BOT': [(107, 1006), 
         (107, 973)], 
      '26580.TOP': [(107, 1008), 
         (107, 1040), 
         (107, 1072), 
         (107, 1648)], 
      '26582.TOP': [(113, 977)], 
      '26685.TOP': [(105, 974)]} 
+2

私は、辞書のすべての値をトラバースするという些細な解決策よりも優れた解決策はありません。 – GolfWolf

答えて

4

私は個人的にはvalues以上のfor-loopを使用しますが、これはデータの上を1回通過するのでスペース効率が良いですが、読みにくい1ライナーを好む場合は常にreduce :)

>>> import functools, itertools 
>>> def max_tuple(t1, t2): return max(t1[0],t2[0]), max(t1[1],t2[1]) 
... 
>>> ts = itertools.chain.from_iterable(roi.values()) 
>>> functools.reduce(max_tuple, ts) 
(113, 1648) 

メモ:スペース効率がよいことに注意してください。あなたはスピードを心配している場合は、ループを使用するか、または、あなたが還元作用のために、この代替実装試すことができます。私のために大幅に高速テストしてい

>>> def max_tuple2(t1, t2): 
...  (a,b), (x,y) = t1, t2 
...  return (a if a > x else x, b if b > y else y) 
... 

を、のは大きなテスト-dictのを作ってみよう:

>>> roi2 = {k+str(i): v*100 for k, v in roi.items() for i in range(100)} 

そして今、いくつかのテスト:

>>> timeit.timeit('ts = itertools.chain.from_iterable(roi2.values()); functools.reduce(max_tuple, ts)', 'from __main__ import functools, itertools, max_tuple, roi2;', number=100) 
4.612322789034806 
>>> timeit.timeit('ts = itertools.chain.from_iterable(roi2.values()); functools.reduce(max_tuple2, ts)', 'from __main__ import functools, itertools, max_tuple2, roi2;', number=100) 
1.7526514289784245 

ので、よく二倍以上の速さmax_tuple2を使用。しかし、速度が問題であれば、ナイーブなforloopアプローチを使用してください。ここで@AdiCのソリューションである、ビットを清書:

>>> def max_from_values(d): 
...  m1 = m2 = float('-inf') 
...  for tlist in d.values(): 
...   for a, b in tlist: 
...    if a > m1: 
...     m1 = a 
...    if b > m2: 
...     m2 = b 
...  return m1, m2 
... 
>>> max_from_values(roi2) 
(113, 1648) 

そして、それがうまく三回最速以前よりも早く、元ののほぼ10倍高速オーバーで、見て:

>>> timeit.timeit('max_from_values(roi2)', 'from __main__ import max_from_values, roi2;', number=100) 
0.4867470810422674 
+0

です。これは非常に驚くべきことです純粋なfor-loopアプローチがより高速であることを示します。それはなぜですか? – empty

+0

@emptyそれは驚くべきことではありません。ジェネレータ表現、ジップイングなどのようなイテレータ構造のほとんどは、オーバーヘッドが大きくなります。 –

3

これを試してみてください:

x = 0 
y = 0 

for key in roi: 

    foo = roi[key] 

    for item in foo: 

     if item[0] > x: 
      x = item[0] 

     if item[1] > y: 
      y = item[1] 

このプログラムは、辞書の各キーをループします。各タプルをループし、 'x'と 'y'の値を比較します。

私は各タプルの最初の要素が 'x'で、2番目の要素が 'y'であると仮定しています。

+1

このアプローチは最も簡単で、実際のコードではおそらく使用しますが、推奨するのは 'value for roi.values()'と 'for a、b in value:' –

4

基本的な考え方:すべてのx値とすべてのy値のリストを取得し、それらの個々のリストのそれぞれの最大値を取得します。

import itertools 
x,y = zip(*itertools.chain(*roi.values())) 
print(max(x),max(y)) 

説明:roi.values()は、キーと値のペアからすべての値を取得しますが、その後、itertools.chain(*...)は1つのリストに2タプルのリストを組み合わせ、そして最終的にはzip(*...)はリストを反転させているので、代わりにk 2のリストの2つのk-タプルがあります。これは、のmaxを得ることができます。

2
list(map(max, zip(*[(x, y) for pair in roi.values() for x, y in pair]))) 
# [113, 1648] 
関連する問題