Print dict in sorted order

K

Kamilche

I have a code snippet here that prints a dict in an arbitrary order.
(Certain keys first, with rest appearing in sorted order). I didn't
want to subclass dict, that's error-prone, and overkill for my needs. I
just need something that returns a value like dict.__str__, with a key
ordering I specify.

If you have any opinions on how it could be made better, I'm all ears!



def DictToString(d, preferred_order = ['gid', 'type',
'parent', 'name']):
' Return a string containing the sorted dict'
keys = d.keys()
keys.sort()
sortmax = len(preferred_order)
for i in range(sortmax-1, -1, -1):
sortkey = preferred_order
try:
index = keys.index(sortkey)
except ValueError:
continue
temp = keys[index]
del keys[index]
keys.insert(0, temp)
s = []
s.append('{')
max = len(keys)
for i in range(max):
key = keys
val = d[key]
s.append(repr(key))
s.append(': ')
s.append(repr(val))
if i < max-1:
s.append(', ')
s.append('}')
return ''.join(s)


def main():
d = {'whatever': 145,
'gid': 12345678901234567890,
'name': 'Name',
'type': 'an egg',
32: 'Thirty-two (32)'}

# Convert dicts to strings
s1 = str(d)
s2 = DictToString(d)
print "Python str:", s1
print "Custom str:", s2

# Verify the strings are different
assert(s1 != s2)

# Convert the strings back to dicts
d1 = eval(s1)
d2 = eval(s2)

# Verify the dicts are equivalent
assert(d1 == d2)

print "\nSuccess!\n"



main()
 
P

Paul Rubin

Kamilche said:
I have a code snippet here that prints a dict in an arbitrary order.
(Certain keys first, with rest appearing in sorted order). I didn't
want to subclass dict, that's error-prone, and overkill for my needs. I
just need something that returns a value like dict.__str__, with a key
ordering I specify.

If you have any opinions on how it could be made better, I'm all ears!

Here's my version. Obviously you could save a line or two here and
there, depending on your stylistic preference.

================================================================

from sets import Set
from cStringIO import StringIO

def DictToString(d, preferred_order = ['gid', 'type',
'parent', 'name']):
r = StringIO()
def out(k, v):
r.write('%s:%s,'% (repr(k), repr(v)))
r.write('{')
for k in preferred_order:
if k in d:
out(k, d[k])
for k in sorted([k1 for k1 in d.keys() if k1 not in Set(preferred_order)]):
out(k, d[k])
r.write('}')
return r.getvalue()
 
F

Fuzzyman

You can always use OrderedDict :

htttp://www.voidspace.org.uk/python/odict.html

from odict import OrderedDict
my_dict = OrderedDict(some_dict.keys())
keys = my_dict.keys()
keys.sort()
my_dict.setkeys(keys)
print my_dict

Of course if your ordering requirement was *that* trivial, you could do
:

from odict import OrderedDict
my_dict = OrderedDict(some_dict.keys())
my_dict.sort()

*Or* you can do :

from odict import SequenceOrderedDict
my_dict = SequenceOrderedDict(some_dict.keys())
keys = my_dict.keys()
keys.sort()
my_dict.keys = keys
print my_dict

All the best,

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml
 
R

Raymond Hettinger

[Kamilche]
I have a code snippet here that prints a dict in an arbitrary order.
(Certain keys first, with rest appearing in sorted order). I didn't
want to subclass dict, that's error-prone, and overkill for my needs. I
just need something that returns a value like dict.__str__, with a key
ordering I specify.

If you have any opinions on how it could be made better, I'm all ears!

Here's one more version to throw in the mix:


from itertools import count, izip

def dict2str(d, preferred_order = ['gid', 'type', 'parent', 'name']):
last = len(preferred_order)
rank = dict(izip(preferred_order, count()))
pairs = d.items()
pairs.sort(key=lambda (k,v): rank.get(k, (last, k, v)))
return '{%s}' % repr(pairs)[1:-1]


d = dict(gid=10, type=20, parent=30, name=40, other=50, rest=60)
print dict2str(d)



Raymond
 
R

Raymond Hettinger

from itertools import count, izip
def dict2str(d, preferred_order = ['gid', 'type', 'parent', 'name']):
last = len(preferred_order)
rank = dict(izip(preferred_order, count()))
pairs = d.items()
pairs.sort(key=lambda (k,v): rank.get(k, (last, k, v)))
return '{%s}' % repr(pairs)[1:-1]

P.S. If you need the string to evaluatable like repr(d), then change
the last line to:

return 'dict(%r)' % pairs
 
M

Michael Spencer

Raymond said:
from itertools import count, izip

def dict2str(d, preferred_order = ['gid', 'type', 'parent', 'name']):
last = len(preferred_order)
rank = dict(izip(preferred_order, count()))
pairs = d.items()
pairs.sort(key=lambda (k,v): rank.get(k, (last, k, v)))
return '{%s}' % repr(pairs)[1:-1]

P.S. If you need the string to evaluatable like repr(d), then change
the last line to:

return 'dict(%r)' % pairs
or:

def dict2str(d, preferred_order = ['gid', 'type', 'parent', 'name']):
pairs = [(item, d[item]) for item in preferred_order]
#preferred_order = set(preferred_order) # if preferred_order is big
pairs.extend(sorted((k, v) for k,v in d.iteritems() if k not in
preferred_order))
return '{%s}' % repr(pairs)[1:-1]

Michael
 
W

Wolfgang Grafen

Use the seqdict.py package:

What is it?
http://home.arcor.de/wolfgang.grafen/Python/Modules/AllOs/DOC/seqdict/

Downloads:
http://home.arcor.de/wolfgang.grafen/Python/Modules/seqdict/seqdict-0.3.zip
http://home.arcor.de/wolfgang.grafen/Python/Modules/AllOs/DOC/HTML/HTMLDoc.zip
http://home.arcor.de/wolfgang.grafen/Python/Modules/AllOs/DOC/HTML/Seqdict.html
http://home.arcor.de/wolfgang.grafen/Python/Modules/AllOs/DOC/HTML/Mseqdict.html

Sorry, this link is broken - have to fix it asap.
http://home.arcor.de/wolfgang.grafen/Python/Modules/Modules.html

seqdict.py has been successfully used in several projects... and it is *easy* and
flexible.

Regards

Wolfgang
I have a code snippet here that prints a dict in an arbitrary order.
(Certain keys first, with rest appearing in sorted order). I didn't
want to subclass dict, that's error-prone, and overkill for my needs. I
just need something that returns a value like dict.__str__, with a key
ordering I specify.
SNIP
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top