对分组对象排序

2024-05-17 13:15:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个物品清单。每个对象有两个属性: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)

Tags: inmapformappingmappingssortedtheoreticalobjectlist
3条回答

只需将sorted与生成所需顺序的key一起使用。由于元组是按字典顺序排列的,因此产生元组的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
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的优秀教程。你知道吗

您可以创建一个自定义比较器来描述两个映射之间的顺序。这比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)

相关问题 更多 >