【问题标题】:python mapping that stays sorted by value保持按值排序的python映射
【发布时间】:2019-11-22 16:50:06
【问题描述】:

有一个SortedDict 类,实现了一个按顺序维护其键的字典,但我找不到任何对其值执行相同操作的等效数据结构,即类似这样的东西:

m = SortedValueMapping(a=3, b=1, c=2)
m.peekitem(0) # b
m.peekitem(-1) # a
m['d'] = 0
m.peekitem(0) # d
m.peekitem(-1) # a

【问题讨论】:

  • 您可以使用heapq,或将sort()sorted() 与任何列表或字典一起使用。这取决于您要达到的目标。
  • 实际上,您链接到的内容包含一个SortedValuesView,这似乎正是您所要求的。
  • @mkrieger1 我也是这么想的,但是 m = SortedDict(a=3, b=1, c=2); [*m.values()] 按预期给出 [3, 1, 2] 而不是 [1, 2, 3]
  • 我的意思是SortedValuesView,而不是SortedDict
  • 另外,你为什么不能用m = dict(a=3, b=1, c=2); sorted(m.values())

标签: python sorting data-structures


【解决方案1】:

以下类是一个快速而肮脏的实现,不能保证效率,但它提供了所需的行为。 如果有人提供更好的答案,我很乐意接受!

class SortedValuesDict:
    def __init__(self, args=None, **kwargs):
        """Initialize the SortedValuesDict with an Iterable or Mapping."""
        from collections import Mapping
        from sortedcontainers import SortedSet
        self.__sorted_values = SortedSet()
        self.__key_value_pairs = {}
        self.__value_key_pairs = {}
        if args is not None:
            iterable = args.items() if isinstance(args, Mapping) else args
            for key, value in iterable:
                self.__setitem__(key, value)
        for key, value in kwargs.items():
            self.__setitem__(key, value)

    def __repr__(self):
        """Get a representation of the SortedValuesDict."""
        return f"SortedValuesDict({', '.join(f'{k}: {v}' for k, v in self)})"

    def __setitem__(self, key, value):
        """Store the key, value pair in the SortedValuesDict."""
        if key in self:
            del self[key]
        self.__key_value_pairs[key] = value
        self.__sorted_values.add(value)
        if value in self.__value_key_pairs:
            self.__value_key_pairs[value].add(key)
        else:
            self.__value_key_pairs[value] = {key}

    def __getitem__(self, key):
        """Get the value corresponding to the key."""
        return self.__key_value_pairs[key]

    def __delitem__(self, key):
        """Remove the given key from the SortedValuesDict"""
        value = self.__key_value_pairs.pop(key)
        keys = self.__value_key_pairs[value]
        keys.remove(key)
        if not keys:
            del self.__value_key_pairs[value]
            self.__sorted_values.remove(value)

    def __contains__(self, key):
        """Test if key is in SortedValuesDict."""
        return key in self.__key_value_pairs

    def __iter__(self):
        """Iterate over the SortedValuesDict items."""
        for value in self.__sorted_values:
            for key in self.__value_key_pairs[value]:
                yield key, value

    def keys(self):
        """Iterate over the SortedValuesDict keys."""
        for value in self.__sorted_values:
            for key in self.__value_key_pairs[value]:
                yield key

    def values(self):
        """Iterate over the SortedValuesDict values."""
        for value in self.__sorted_values:
            for key in self.__value_key_pairs[value]:
                yield value

    def items(self):
        """Iterate over the SortedValuesDict items."""
        yield from self

    def peek(self, pos=0):
        """Peek at the next key for the value at position pos."""
        return next(iter(self.__value_key_pairs[self.__sorted_values[pos]]))

    def peekvalue(self, pos=0):
        """Peek at the value at position pos (default 0)."""
        return self.__sorted_values[pos]

    def peekitem(self, pos=0):
        """Peek at the the next key for the value at position pos."""
        value = self.__sorted_values[pos]
        return next(iter(self.__value_key_pairs[value])), value

    def pop(self, pos=-1):
        """Pop a key corresponding to the value at position pos."""
        value = self.__sorted_values[pos]
        keys = self.__value_key_pairs[value]
        key = keys.pop()
        del self.__key_value_pairs[key]
        if not keys:
            del self.__value_key_pairs[self.__sorted_values.pop(pos)]
        return key

    def popitem(self, pos=-1):
        """Pop an item corresponding to the value at position pos."""
        value = self.__sorted_values[pos]
        keys = self.__value_key_pairs[value]
        key = keys.pop()
        del self.__key_value_pairs[key]
        if not keys:
            del self.__value_key_pairs[self.__sorted_values.pop(pos)]
        return key, value
m = SortedValuesDict(a=3, b=1, c=2)
[*m.values()]  # [1, 2, 3]
[*m]  # [('b', 1), ('c', 2), ('a', 3)] (same as [*m.items()])
m.peekitem(0)  # ('b', 1)
m.peekitem(-1)  # ('a', 3)
m['d'] = 0
m.peekitem(0)  # ('d', 0)
m.peekitem(-1)  # ('a', 3)
m['e'] = 0
m  # SortedValuesDict(d: 0, e: 0, b: 1, c: 2, a: 3)
m.peekitem(0)  # (('d', 0), ('e', 0))
m.pop()  # 'a' (from back)
m.pop(0)  # 'd'
m  # SortedValuesDict(e: 0, b: 1, c: 2)
m.popitem()  # ('c', 2)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-29
    • 2021-12-07
    • 2011-11-19
    • 2018-01-15
    • 2016-05-21
    • 1970-01-01
    • 2011-02-11
    • 2021-03-01
    相关资源
    最近更新 更多