2011-05-28 85 views
5

有沒有更好的方式來排序嵌套元組值的列表比寫一個itemgetter替代提取嵌套元組值:排序列表值

def deep_get(*idx): 
    def g(t): 
     for i in idx: t = t[i] 
     return t 
    return g 

>>> l = [((2,1), 1),((1,3), 1),((3,6), 1),((4,5), 2)] 
>>> sorted(l, key=deep_get(0,0)) 
[((1, 3), 1), ((2, 1), 1), ((3, 6), 1), ((4, 5), 2)] 
>>> sorted(l, key=deep_get(0,1)) 
[((2, 1), 1), ((1, 3), 1), ((4, 5), 2), ((3, 6), 1)] 

我想過使用撰寫,但是這不在標準庫中:

sorted(l, key=compose(itemgetter(1), itemgetter(0)) 

有沒有什麼我錯過了在庫中,這將使這段代碼更好?

該實施應該與100k項目合理合作。

上下文:我想排序一個直方圖項目的字典。鍵是一個元組(a,b),值是計數。最後,這些項目應按降序a和b排序。另一種方法是平滑元組並直接使用itemgetter,但這樣會產生大量的元組。

+0

有沒有我知道的。你的方法很好,因爲它是恕我直言。 – 2011-05-28 16:25:00

+0

「實施應該合理地處理10萬件物品。」 - 這條線是不必要的;所有使用'sort'的實現都可以在100k條件下合理運行 – ninjagecko 2011-05-28 18:18:33

+0

@ninjagecko如果對3個條目或100k或1T進行排序,實現將會有所不同。 – 2011-05-30 06:55:58

回答

8

是的,你可以只使用一個key=lambda x: x[0][1]

+0

'itemgetter(0)'比'lambda x:x [0]'更快嗎? 'compose(itemgetter(1),itemgetter(0))','lambda x:x [0] [1]'和'deep_get'具有相同的性能特徵嗎? – 2011-05-28 16:23:44

+0

lambda幾乎肯定會比所有這些都快,但由於排序,它仍然是'O(N log(N))',所以我不會擔心太多;有可能更好的東西來優化 – ninjagecko 2011-05-28 16:34:49

+1

我認爲itemgetter會比lambda更快,因爲它是用C編寫的。你爲什麼認爲lambda更快? – utdemir 2011-05-28 16:46:05

2

你的做法是相當不錯的,因爲你的數據結構。

另一種方法是使用另一種結構。

如果你想要速度,去因子標準NumPy是要走的路。它的工作是有效處理大型數組。它甚至爲你的數組提供了一些很好的排序例程。這裏是你如何會在寫你的排序上的計數,然後(A,B):

>>> arr = numpy.array([((2,1), 1),((1,3), 1),((3,6), 1),((4,5), 2)], 
        dtype=[('pos', [('a', int), ('b', int)]), ('count', int)]) 
>>> print numpy.sort(arr, order=['count', 'pos']) 
[((1, 3), 1) ((2, 1), 1) ((3, 6), 1) ((4, 5), 2)] 

這是非常快的(它是用C實現的)。

如果你想堅持使用標準的Python,包含(count,a,b)元組的列表會自動按照你想要的方式被Python排序(它使用元組的字典順序)。

0

我比較了兩種類似的解決方案。第一個使用一個簡單的λ:

def sort_one(d): 
    result = d.items() 
    result.sort(key=lambda x: (-x[1], x[0])) 
    return result 

註上x[1]負,因爲你想的那種要在數下降。

第二個利用了Python中的sort穩定的事實。首先,我們按(a, b)排序(升序)。然後我們排序算,下降:

def sort_two(d): 
    result = d.items() 
    result.sort() 
    result.sort(key=itemgetter(1), reverse=True) 
    return result 

第一個是快10-20%(包括小型和大型數據集),和0.5秒下既要完成我的Q6600(使用一個核心)爲10萬項。所以避免創建元組似乎沒有多大幫助。

1

這可能是你的做法有點更快的版本:

l = [((2,1), 1), ((1,3), 1), ((3,6), 1), ((4,5), 2)] 

def deep_get(*idx): 
    def g(t): 
     return reduce(lambda t, i: t[i], idx, t) 
    return g 

>>> sorted(l, key=deep_get(0,1)) 
[((2, 1), 1), ((1, 3), 1), ((4, 5), 2), ((3, 6), 1)] 

這可能是縮短爲:

def deep_get(*idx): 
    return lambda t: reduce(lambda t, i: t[i], idx, t) 

甚至只是簡單地寫出:

sorted(l, key=lambda t: reduce(lambda t, i: t[i], (0,1), t))