1

I have written this code:

n=5
dizN={}
for q in range(0,n+1):
    h=n-q
    dizN['a'+str(q)+'p'+str(h)]=0

that creates such a dictionary:

dizN

Out[120]: {'a0p5': 0, 'a1p4': 0, 'a2p3': 0, 'a3p2': 0, 'a4p1': 0, 'a5p0': 0}

Note that "n" is the basic parameter for my code. As you can see, the sum of integers present in dict keys string is always =n (=5 in this case, where n=5).

It is important for me (for more difficult purposes in my program) that, for every n anyone can choose, the dict is ordered in this way:

{'a0p(n)': 0, 'a1p(n-1)': 0, ....., 'a(n-1)p1': 0, 'a(n)p0': 0}

My code is ok, but only for n<10. If n is >=10, this is what happens: (n=12) dizN:

Out[121]: 
  {'a0p12': 0,
   'a10p2': 0,
   'a11p1': 0,
   'a12p0': 0,
   'a1p11': 0,
   'a2p10': 0,
   'a3p9': 0,
   'a4p8': 0,
   'a5p7': 0,
   'a6p6': 0,
   'a7p5': 0,
   'a8p4': 0,
   'a9p3': 0}

As you can see the interpreter follows alphanumeric sorting;

Anybody know if there is a way to obtain the same dict sorted this way:

{'a0p12': 0,
 'a1p11': 0,
 'a2p10': 0,
 'a3p9': 0,
 'a4p8': 0,
 'a5p7': 0,
 'a6p6': 0,
 'a7p5': 0,
 'a8p4': 0,
 'a9p3': 0,
 'a10p2': 0,
 'a11p1': 0,
 'a12p0': 0}

?

I know that dictionaries are basically non sortable, but i hope somebody knows some trick to obtain my purpose anyway :)

Thanks a lot!

mik.ferrucci
  • 121
  • 1
  • 2
  • 13
  • You write multiple times about ordering a dictionary, but Python's dictionaries cannot be ordered. Perhaps you should look at `OrderedDict`. – Rory Daulton Oct 17 '16 at 14:05
  • The whole point of a dictionary is that it isn't ordered. It's a hash table. – Daniel Oct 17 '16 at 14:11
  • The sorting criteria i would like to follow is "simply" by the first integer in dict keys strings, considered as an integer (not string) ascending. Or, to explain better, by the integer that follows letter 'a' in the strings that are the keys of my dict: 'a(integer)p(integer)'. – mik.ferrucci Oct 17 '16 at 14:18

1 Answers1

1

dicts are unordered, so to get the order you are going to have to sort the items and use an OrderedDict to maintain the sorted order. To get the order you want you can create tuples from the groups of integers so you sort as integers in lexicographical order:

from itertools import groupby
from collections import OrderedDict
d = {'a0p12': 0, 'a10p2': 0, 'a11p1': 0, 'a12p0': 0, 'a1p11': 0, 'a2p10': 0,
     'a3p9': 0, 'a4p8': 0, 'a5p7': 0, 'a6p6': 0, 'a7p5': 0, 'a8p4': 0, 'a9p3': 0}

def key_func(x):
    """'a0p12' -> (0, 12)"""
    return tuple(int("".join(v)) for k,v in groupby(x[0], key=str.isdigit) if k)
od = OrderedDict(sorted(d.items(), key=key_func))

print(od)

Which would give you:

OrderedDict([('a0p12', 0), ('a1p11', 0), ('a2p10', 0), ('a3p9', 0), 
('a4p8', 0), ('a5p7', 0), ('a6p6', 0), ('a7p5', 0), ('a8p4', 0), 
('a9p3', 0), ('a10p2', 0), ('a11p1', 0), ('a12p0', 0)])

You could also use a regex to find the groups of digits:

from collections import OrderedDict
import re

d = {'a0p12': 0, 'a10p2': 0, 'a11p1': 0, 'a12p0': 0, 'a1p11': 0, 'a2p10': 0,
     'a3p9': 0, 'a4p8': 0, 'a5p7': 0, 'a6p6': 0, 'a7p5': 0, 'a8p4': 0, 'a9p3': 0}



def key_func(x,patt=re.compile("\d+")):
    """'a0p12' -> (0, 12)"""
    return tuple(map(int, patt.findall(x[0])))

od = OrderedDict(sorted(d.items(), key=key_func))

print(od)
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321