2012-01-21 83 views
3
def greatest(values): 
    value_generator = (v for k,v in values) 
    max_value = max(value_generator) 
    return (k for k,v in values if v == max_value) 

sample_data = (('id1', 3), ('id2', 5), ('id3', 5)) 
items = list(greatest(sample_data)) # Should produce ['id2', 'id3'] 

MapReduce任何人?有沒有寫下列最大值函數的pythonic方法:

回答

2

事實上,根據我的測試,你的greatest版本速度更快 - 通過比特,反正:

>>> def greatest_orig(values): 
...  value_generator = (v for k,v in values) 
...  max_value = max(value_generator) 
...  return (k for k,v in values if v == max_value) 
... 
>>> def greatest_max_key(values): 
...  max_value = max(values, key=itemgetter(1))[1] 
...  return (k for k,v in values if v == max_value) 
... 
>>> sample_data = tuple(('id' + str(i), random.randrange(0, 1000)) for i in range(10000)) 
>>> list(greatest_orig(sample_data)) == list(greatest_max_key(sample_data)) 
True 
>>> %timeit list(greatest_orig(sample_data)) 
1000 loops, best of 3: 1.67 ms per loop 
>>> %timeit list(greatest_max_key(sample_data)) 
1000 loops, best of 3: 1.74 ms per loop 

當然,如果你不喜歡你的分配生成器的名稱,你可以通過發電機最大直接 - 方式超過max(values, key=itemgetter(1))[1]可讀性,恕我直言:

>>> def greatest_max_iter(values): 
...  max_value = max((v for k, v in values)) 
...  return (k for k, v in values if v == max_value) 
...             
>>> list(greatest_orig(sample_data)) == list(greatest_max_iter(sample_data)) 
True 
>>> %timeit list(greatest_max_iter(sample_data)) 
1000 loops, best of 3: 1.67 ms per loop 

Python允許你做的事情時,這樣的省略外的括號:

>>> def greatest_max_iter(values): 
...  max_value = max(v for k, v in values) 
...  return (k for k, v in values if v == max_value) 
... 

但對於原因,我不明白,做這樣的說法是稍微慢一些:

>>> %timeit list(greatest_max_iter(sample_data)) 
1000 loops, best of 3: 1.69 ms per loop 

這些都是真實的微優化,不可能多大關係。但我認爲或max((v for k, v in values))的可讀性優於max(values, key=itemgetter(1))[1]

3

你可以計算MAX_VALUE這樣的:

max_value = max(sample_data, key=lambda x: x[1])[1] 

正如你也可以使用itemgetter爲MAX()功能鍵的評論說:

import operator 
max_value = max(sample_data, key=operator.itemgetter(1))[1] 

所以,你的代碼是(與itemgetter並直接返回一個列表):

import operator 
def greatest(values): 
    max_value = max(values, key=operator.itemgetter(1))[1] 
    return [k for k,v in values if v == max_value] 
+0

這隻會返回一個值。 – Johnsyweb

+1

@Johnsyweb,這正好代替了OP max_value的計算。編輯以防止誤解 – joaquin

3

內置max功能有一個可選的key參數,可以自定義排序數據。下面是排序在數據元組的第二個項目,並返回中最大的一個:

>>> sample_data = ('id1',3),('id2',5),('id3',5) 
>>> def greatest(values): 
... m = max(values,key=lambda n: n[1])[1] 
... return [k for k,v in values if v==m] 
... 
>>> greatest(sample_data) 
['id2', 'id3'] 
+4

'operator.itemgetter(1)'是拼寫'lambda n:n [1]'的等價且更快的方式。 – SingleNegationElimination

3

試試這個:

from operator import itemgetter 

def greatest(values): 
    m = max(values, key=itemgetter(1))[1] 
    return [k for k,v in values if v == m] 

而且使用這樣的:

>>> sample_data = (('id1', 3), ('id2', 5), ('id3', 5)) 
>>> greatest(sample_data) 
['id2', 'id3'] 
+0

@senderle謝謝,修正它。 –

1

如果你想使用map

>>> sample_data = (('id1', 3), ('id2', 5), ('id3', 5)) 
>>> max_value = max(sample_data, key=lambda x: x[1]) 
>>> map(lambda x: x[0], filter((lambda x: x[1]==max_value), sample_data)) 
['id2', 'id3'] 
+0

+1爲好的功能鍛鍊。然而,不確定是否更多pythonic。 – joaquin

相關問題