2012-09-27 49 views
7

我使用namedtuple類很多。我一直在想,如果有一種很好的方法來爲這樣的類實現自定義排序,即使默認排序鍵不是第一個元素(然後是第二個,第三個等)的namedtuple。在namedtuple類上自定義排序

我的第一反應是實現__lt____eq__total_ordering做休息(它填補了樂,NE,GT,GE):

from collections import namedtuple 
from functools import total_ordering 


@total_ordering 
class B(namedtuple('B', 'x y')): 
    def __lt__(self, other): 
     return self.y < other.y 

但是:

def test_sortingB(): 
    b1 = B(1, 2) 
    b2 = B(2, 1) 
    assert b2 < b1 # passes 
    assert b2 <= b1 # fails 

哦,正確... total_ordering只填寫了其他方法if they are missing。由於tuple/namedtuple有這樣的方法,total_ordering對我來說沒有任何幫助。

所以我想我的選擇是

  1. 停止使用namedtuple,只是建立自己的無聊的課,繼續使用total_ordering使用namedtuple
  2. 保管和使用namedtuple和插入實現所有6種比較方法
  3. 保持作爲第一個字段的排序值。幸運的是,我沒有太多類的實例,但通常我只是依靠字段的順序來初始化它們,這可能是討厭的。也許這是一個壞習慣。

有關解決此問題的最佳方法的建議?

+0

爲什麼不只是按照您想排序的順序創建namedtuple字段? – BrenBarn

+0

我沒有意識到我想排序/最大等,直到我已經創建並使用它一段時間。所以我現在可以添加一個領先的領域作爲排序領域,但它可能有點破壞性。 – pfctdayelise

+1

但是你如何使用namedtuple?關於namedtuple的好處是它可以讓你按名稱訪問項目,所以你可以改變你的namedtuple,讓字段按照正確的順序,而不會影響你的代碼,只要你按名稱訪問字段(這可能是你在做什麼,或者爲什麼使用namedtuple?)。 – BrenBarn

回答

10

OPTION 1.使用mixin和total_ordering適用於

@total_ordering 
class B_ordering(object): 
    __slots__ =()     # see Raymond's comment 
    def __lt__(self, other): 
     return self.y < other.y 

class B(B_ordering, namedtuple('B', 'x y')): 
    pass 

選項2.根據total_ordering製作屬於自己的裝飾,只需使用

+1

+1,mixin解決方案很好。 – nneonneo

+0

選項1和選項2的開銷是否有顯着差異? – Will

+0

+1。選項1是total_ordering問題的直接解決方案,只填寫缺失值。 @ Will選項1的開銷幾乎爲零(在方法解析順序中增加了一個額外的步驟@JohnLaRooy,我建議在你的Option1中加入\ _ \ _ slots \ _ \ _ =()以恢復內存效率 –

1

我的建議是創建您的namedtuple與其他你希望他們排序的字段。您可能需要更改代碼中創建值的部分(例如,將someTuple("name", 24)更改爲someTuple(24, "name"),但通常創建的值比使用的位置更少,因此這應該不會太大。避免了編寫所有的比較方法的麻煩,並作爲獎金也避免了這些自定義的比較方法叫所有的時間的額外性能開銷。

3

如果,你的問題意味着,你的興趣只在由備用鑰匙排序 namedtuples,爲什麼不使用排序/整理key參數與attrgetter功能:

>>> from collections import namedtuple 
>>> from operator import attrgetter 
>>> P = namedtuple("P", "x y") 
>>> p1 = P(1, 2) 
>>> p2 = P(2, 1) 
>>> sorted([p1, p2], key=attrgetter("y")) 
[P(x=2, y=1), P(x=1, y=2)] 

你可以去甚至進一步並定義您自己的排序功能:

>>> from functools import partial 
>>> sortony = partial(sorted, key=attrgetter("y")) 
>>> sortony([p1, p2]) 
[P(x=2, y=1), P(x=1, y=2)] 
+0

排序字段現在還不存在,所以我需要添加它或者使用一個cmp方法來查看2個字段並且對它們做一些邏輯(我的示例代碼過於簡化) – pfctdayelise