Python 3.7+: Access elements of a dictionary by order

385 Views Asked by At

So I understand that, since Python 3.7, dicts are ordered, but the documentation doesn't seem to list methods of using said ordering. For example, how do I access say the first element of the dict by order, independent of keys? What operations can I do with the ordered dict?

As an example, I am working on implementing a Least Frequently Used cache, where I need to track not only the number of uses of a key, but also use Least Recently Used information as a tie break. I could use a dict of queues to implement a priority queue, but then I lose O(1) lookup within the queue. If I use a dict of dicts I can retain the advantages of a hashed set AND implement it as a priority queue... I think. I just need to be able to pop the first element of the dictionary. Alas, there is no dict.popleft().

For now I am converting the keys to a list and just using the first element of the list, but while this works (the dict is keeping ordering), the conversion is costly.

LFU_queue = collections.defaultdict(collections.defaultdict)
LFU_queue[1].update({"key_1":None})
LFU_queue[1].update({"key_32":None})
LFU_queue[1].update({"key_6":None})

#Inspecting this, I DO get what I expect, which is a 
#dict of dicts with the given ordering:
#{ 1: {"key_1":None}, {"key_32":None}, {"key_6":None}}

#here is where I'd love to be able to do something like
# LFU_queue[1].popleft() to return {"key_1":None}

list(LFU_queue[1])[0] works, but is less than ideal
1

There are 1 best solutions below

0
relent95 On

As others commented, using OrderedDict is the right choice for that problem. But you can also use the bare dict using the items() like this.

d = {}
d['a'] = 1
d['b'] = 2
first_pair = next(iter(d.items()), None)

If you are interested, see PEP 372 and PEP 468 for the history of dictionary ordering.

With PEP 468, you can implement a syntax sugar like this.

from ctypes import Structure, c_int, c_ulong

def c_fields(**kwargs):
    return list(kwargs.items())

class XClientMessageEvent(Structure):
    _fields_ = c_fields(
        type = c_int,
        serial = c_ulong,
        send_event = c_int,
        ...
    )