按照子字典的键定义排序顺序对Python字典键进行排序

2024-09-30 10:27:02 发布

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

我的问题是another question的一个扩展,其中OP有一个字典,如下所示,并希望根据子字典键对主键进行排序

myDict = {
    'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'},
    'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'},
    'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'},
    'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'},
    'ABC12346': {'serial_num': 'ABC12346', 'site_location': 'Europe'}
}

建议的(引用如下)解决方案非常有效。在

^{pr2}$

但是,这个解决方案对所有人都按升序排序(降序排序很简单)。我想知道是否可以定义混合排序顺序,比如serial_num按升序,而{}按降序排列?在


Tags: 字典排序serialsitelocation解决方案numsouth
3条回答

如果您确实需要自定义排序顺序,那么您可以使用排序逻辑编写一个自定义对象,该对象将作为下面实际对象的包装器。在

from functools import total_ordering
# total_ordering keeps you from having to write each of
# __gt__, __ge__, __lt__, __le__. It requires __eq__ and one of the
# other comparison functions to be defined and the rest are assumed
# in terms of each other.  (__ge__ = __gt__ or __eq__, __gt__ = not __le__), etc.

@total_ordering
class CustomSorter(object):
    def __init__(self, data):
        self.data = data

    # the properties here are solely to make the code a little more readable
    # in the rich comparators below. You can ignore them if you like.
    @property
    def serial_number(self):
        return self.data[1]["serial_number"]
    @property
    def site_location(self):
        return self.data[1]["site_location"]

    def __eq__(self, other):
        if not isinstance(other, CustomSorter):
            raise NotImplementedError("CustomSorters can only sort with themselves")
        return self.data[1] == other.data[1]

    def __lt__(self, other):
        if not isinstance(other, CustomSorter):
            raise NotImplementedError("CustomSorters can only sort with themselves")
        if self.site_location == other.site_location:
            return self.site_number < other.site_number
        else:
            return not (self.site_location < other.site_location)

然后用传统的装修整理去装饰的步骤。在

^{pr2}$

这可能是最好的,如果你实现一个函数来为你排序。在

def sort_on(sorter, unsorted):
    """sort_on expects @sorter@ to be a class with rich comparison operations
    that is a decorative wrapper around some data to be sorted. Additionally,
    @sorter.data@ should refer to the underlying data structure.
    """

    decorated = [sorter(unsort) for unsort in unsorted]
    decosorted = decorated.sort()
    sorted = [decosort.data for decosort in decosorted]
    return sorted

result = sort_on(CustomSorter, myDict.items())

我认为你使用元组的单一类型的方法是最具Python特征的,所以我会坚持这一点。如果这些值都是数值,那么可以很容易地对任何一个元组值求反,以获得键的那部分的相反顺序,但这里的问题是您想对字符串求反,对吗?所以我们来解决这个问题:

def str_to_neg_ords(s):
    return tuple(-ord(c) for c in s)

现在,您可以将此函数用作键的一部分来执行嵌套词典排序:

^{pr2}$

这是一个解决方案,可能是因为列表排序是stable。我稍微修改了数据以证明它是有效的。在

这个方法在Python documentation中也有规定。在

myDict = {
    'SER12346': {'serial_num': 'SER12346', 'site_location': 'North America'},
    'ABC12346': {'serial_num': 'ABC12345', 'site_location': 'Europe'},
    'ABC12345': {'serial_num': 'ABC12345', 'site_location': 'South America'},
    'SER12345': {'serial_num': 'SER12345', 'site_location': 'North America'},
    'SER12347': {'serial_num': 'SER12347', 'site_location': 'South America'}
}

result = sorted(myDict.items(), key=lambda x: x[1]['site_location'], reverse=True)
result = sorted(result, key=lambda x: x[1]['serial_num'])

# [('ABC12345', {'serial_num': 'ABC12345', 'site_location': 'South America'}),
#  ('ABC12346', {'serial_num': 'ABC12345', 'site_location': 'Europe'}),
#  ('SER12345', {'serial_num': 'SER12345', 'site_location': 'North America'}),
#  ('SER12346', {'serial_num': 'SER12346', 'site_location': 'North America'}),
#  ('SER12347', {'serial_num': 'SER12347', 'site_location': 'South America'})]

相关问题 更多 >

    热门问题