1

I have a dictionary like this:

>>> dictionary = {34: "martsz", 79: "David", "": "Kathy", 63: "Daniel"}

I want to sort it by keys without changing the "" position so it can become like this:

>>> dictionary
{34: "martsz", 63: "Daniel", "": "Kathy", 79: "David"}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
tuz
  • 41
  • 4
  • 4
    Dictionaries are not ordered – Phoenixo Mar 10 '20 at 21:44
  • 4
    That's a very strange dictionary format, using both integer and string keys. What is your use case? There's probably a better way to store this data--for example, a list of tuples or objects. – John Kugelman Mar 10 '20 at 21:47
  • 1
    @phoenixo How long are people going to keep claiming that? – Kelly Bundy Mar 10 '20 at 21:50
  • 1
    In addition to @HeapOverlfow's comment: Standard dicts are considered to be ordered since Python 3.7. However, we should not rely on this fact as there might be some cases where order of standard dicts is neglected. For further information see https://stackoverflow.com/q/50872498/3991125 providing several links to docs and changelog and a detailed explanation on the topic of dict order. – albert Mar 10 '20 at 21:52
  • @HeapOverflow : my bad, I didn't know this feature – Phoenixo Mar 10 '20 at 22:03

2 Answers2

3

since python3.6 dictionaries are insertion ordered, so if you have a python version >= 3.6 you can use:

dictionary = {34: "martsz", 79: "David", "": "Kathy", 63: "Daniel"}

i = next(i for i, e in enumerate(dictionary) if e == "")

idx = sorted(e for e in dictionary if e != "")
idx.insert(i, "")
dictionary = {e: dictionary[e] for e in idx}
dictionary

output:

{34: 'martsz', 63: 'Daniel', '': 'Kathy', 79: 'David'}

for other python versions you can use OrderedDict

kederrac
  • 16,819
  • 6
  • 32
  • 55
1

Solution

This uses collections.OrderedDict.

Short Answer

You could use the following functions and use OrderedDict.

from collections import OrderedDict

d = {34: "martsz", 79: "David", "": "Kathy", 63: "Daniel"}
d = OrderedDict(**d)
get_sorted_dict(d, target_key='')

Output:

OrderedDict([('34', 'martsz'),
             ('63', 'Daniel'),
             ('', 'Kathy'),
             ('79', 'David')])

Long Answer

This includes the custom functions.

from collections import OrderedDict

def get_sorted_keys(keys, target_key='') -> list:
    """Returns a list of sorted keys with 
       index of target_key kept unchanged.
    """
    keys = [str(k) for k in keys]
    sorted_keys = sorted(keys)
    sorted_keys.pop(sorted_keys.index(''))
    target_key_index = keys.index(target_key)
    sorted_keys.insert(target_key_index, target_key)
    return sorted_keys

def get_sorted_dict(d:dict, target_key='') -> OrderedDict:
    """Returns a dictionary sorted by the keys, while 
       keeping the index of the target_key unchanged.

    """
    sorted_keys = get_sorted_keys(keys = d.keys(), 
                                  target_key = target_key)
    sorted_dict = OrderedDict()
    for k in sorted_keys:
        temp = {k: d.get(int(k))} if not (k==target_key) else {k: d.get(k)}        
        sorted_dict.update(temp.copy())
    return sorted_dict  

##----------------- Implementation ------------------
d = {34: "martsz", 79: "David", "": "Kathy", 63: "Daniel"}
d = OrderedDict(**d)
get_sorted_dict(d, target_key='')
CypherX
  • 7,019
  • 3
  • 25
  • 37