I am retrieving data from Postgres (jsonb type) and I need to return an
OrderedDict that has a predictable order for human and machine consumption. There are some common(ish) keys that should be used to direct precedence of values of common types (based on a predefined order and if
sort_order is defined). Otherwise, sort order should fall back to key based lexicographic ordering.
The general intent is to have a predictable, 'sane', represenation of composite dicts.
The basic algorithm is:
- Dicts come before lists
- Values that are NOT iterables or mapping take precedence over objects that are.
- Values of the same type whose keys are not in sort_order are considered equal and should be sorted lexicographically.
- Obj A takes precedence over Obj B
if type(A) == type(B) and  in sort_order not B in sort_order
if all([type(A) == type(B), A in sort_order, B in sort_order])then the index position of the object key is the precedence determinant.
I have attempted several implementations, but I have not been able to come up with anything that I would consider pythonic/elegant.
Here is the latest incarnation:
# -*- coding: utf-8 -*- import json from collections import OrderedDict def dict_sort(obj, sort_order=None): def seq(s, o=None, v=None): return str(s) + str(o) + str(v) if o is not None else str(s) order_seq = None if sort_order is not None and obj in sort_order: order_seq = [i for i, v in enumerate(sort_order) if v == obj] if isinstance(obj, dict): return seq(2, order_seq, obj) if order_seq else seq(3) elif isinstance(obj, list): return seq(4, order_seq, obj) if order_seq else seq(5) else: return seq(0, order_seq, obj) if order_seq else seq(1) def comp_sort(obj, sort_order=None): data = OrderedDict() if isinstance(obj, dict): for key, value in sorted(obj.items(), key=lambda d: dict_sort(d, sort_order)): if isinstance(value, dict) or isinstance(value, list): data[key] = comp_sort(value, sort_order) else: data[key] = value elif isinstance(obj, list): try: return sorted(obj) except: items =  for value in obj: if isinstance(value, dict) or isinstance(value, list): items.append(comp_sort(value, sort_order)) else: items.append(value) return items return data # thx herk
Here is a sample data set.