mik.ferrucci - 7 months ago 33

Python Question

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 :)

Here I have written to find original solutions!

Thanks a lot!

Answer

*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)])
```