2013-07-10 52 views
1

我有一個對象列表。每個對象都有兩個屬性:DispNameMachIDDispName可以從theoretical開始,也可以是其他內容。排序分組對象

我需要以下列方式排序此列表:

  • 首字母順序排列每MachID
      每個子組 MachID第一內
    • 其中名稱與theoretical
    • 然後開始按字母順序排序的其他對象的對象。

這是代碼我現在有,其工作方式和生產所需的輸出,但我想知道如果我能寫這個更Python,也許利用的groupby? (我的駱駝裝的藉口)。

from collections import defaultdict, namedtuple 
from operator import attrgetter 

Mapping = namedtuple('Mapping', ['DispName', 'MachID']) 

objectList = [Mapping('map 2 (MT1)', 'MT1'), 
      Mapping('theoretical (MT1)', 'MT1'), 
      Mapping('map 3 (MT2)', 'MT2'), 
      Mapping('theoretical (MT2)', 'MT2'), 
      Mapping('map 1 (MT1)', 'MT1'), 
      Mapping('map 2 (MT2)', 'MT2')] 

def complexSort(objectList): 
    objectDict = defaultdict(list) 
    sortedMappingList = [] 
    # group by machine ID 
    for obj in objectList: 
     objectDict[obj.MachID].append(obj) 
    # loop over the mappings sorted alphabetically by machine ID 
    for machID in sorted(objectDict.keys()): 
     mappings = objectDict[machID] 
     nonTheoreticalMappings = [] 
     for mapping in mappings: 
      if mapping.DispName.startswith('theoretical'): 
       # if we encounter the theoretical mapping, add it first 
       sortedMappingList.append(mapping) 
      else: 
       # gather the other mappings in a sublist 
       nonTheoreticalMappings.append(mapping) 
     # and add that sublist sorted alphabetically 
     sortedMappingList.extend(sorted(nonTheoreticalMappings, 
            key=attrgetter('DispName')))   
    return sortedMappingList 

for mapping in complexSort(objectList): 
    print mapping.DispName 

產地:

theoretical (MT1) 
map 1 (MT1) 
map 2 (MT1) 
theoretical (MT2) 
map 2 (MT2) 
map 3 (MT2) 

回答

2
import collections 
import operator 
import itertools as IT 

Mapping = collections.namedtuple('Mapping', ['DispName', 'MachID']) 

objectList = [Mapping('map 2 (MT1)', 'MT1'), 
      Mapping('theoretical (MT1)', 'MT1'), 
      Mapping('map 3 (MT2)', 'MT2'), 
      Mapping('theoretical (MT2)', 'MT2'), 
      Mapping('map 1 (MT1)', 'MT1'), 
      Mapping('map 2 (MT2)', 'MT2')] 

sortedMappingList = sorted(objectList, 
      key=lambda mapping: 
          (mapping.MachID, 
          not mapping.DispName.startswith('theoretical'), 
          mapping.DispName)) 

for key, group in IT.groupby(sortedMappingList, key=operator.attrgetter('MachID')): 
    for g in group: 
     print(g.DispName) 

產生

theoretical (MT1) 
map 1 (MT1) 
map 2 (MT1) 
theoretical (MT2) 
map 2 (MT2) 
map 3 (MT2) 

有上How to sort using key functions一個很好的教程,這裏。

3

只需使用sortedkey產生你想要的順序。由於元組按字典順序排列,因此產生元組的key應該工作得很好。

def sort_key(thing): 
    return (thing.MachID, not thing.DispName.startswith('theoretical')) 

sorted(objectList, key=sort_key) # returns a list sorted the way you want 
1

您可以創建一個自定義比較器來描述兩個Mappings應該如何相互排序。這比你的complexSort更清潔,因爲該函數的唯一職責是比較兩個對象,並將實際的排序留給Python。

from collections import namedtuple 

Mapping = namedtuple('Mapping', ['DispName', 'MachID']) 


def cmp_Mapping(a,b): 
    #first, sort alphabetically by MachID 
    if a.MachID != b.MachID: 
     return cmp(a.MachID, b.MachID) 
    else: 
     #if MachIDs match, and one starts with "theoretical", it should go first. 
     if a.DispName.startswith("theoretical") and not b.DispName.startswith("theoretical"): 
      return -1 
     elif b.DispName.startswith("theoretical") and not a.DispName.startswith("theoretical"): 
      return 1 
     #everything else is ordered alphabetically. 
     else: 
      return cmp(a.DispName, b.DispName) 

objectList = [Mapping('map 2 (MT1)', 'MT1'), 
      Mapping('theoretical (MT1)', 'MT1'), 
      Mapping('map 3 (MT2)', 'MT2'), 
      Mapping('theoretical (MT2)', 'MT2'), 
      Mapping('map 1 (MT1)', 'MT1'), 
      Mapping('map 2 (MT2)', 'MT2')] 

for mapping in sorted(objectList, cmp = cmp_Mapping): 
    print mapping.DispName 

結果:

theoretical (MT1) 
map 1 (MT1) 
map 2 (MT1) 
theoretical (MT2) 
map 2 (MT2) 
map 3 (MT2)