1

I have a list of dictionary for ex:

names = [{'Mark':'Volvo'}, {'John':'BMW'}, {'Eliza':'Merci'}, {'Calen':'Audi'}]

I would like to set the explicit ordering by the key names of the dictionary.

For example if I give this order:

['John','Mark','Calen','Eliza']

The expected output would be:

[{'John':'BMW'},{'Mark':'Volvo'},{'Calen':'Audi'},{'Eliza':'Merci'}]

I want to add a custom logic order. To be displayed through the template by their names, based on how I defined the order of their names.

sage07
  • 83
  • 8
Szocs Arnold
  • 55
  • 1
  • 7
  • 4
    What's the logic of this order? Or is the order provided separately as a list, like `['John', 'Mark', ...]` or `['BMW', 'Volvo']`? – bereal Jun 26 '20 at 07:07
  • "I would like to set the explicit ordering manually" could you please elaborate on this? – S M Vaidhyanathan Jun 26 '20 at 07:10
  • I would add that the answer is well-defined only if all dicts have exactly one element, which you may want to clarify. If so, you may be better off storing the data as a single dict ('{str: str}' if each key has one value or '{str: [str]}' if some keys have many values). Then, [this](https://stackoverflow.com/questions/9001509/how-can-i-sort-a-dictionary-by-key) should answer your question. – hilberts_drinking_problem Jun 26 '20 at 07:32
  • Yes, dicts have exactly one element. – Szocs Arnold Jun 26 '20 at 07:35
  • But I do not want to sort it alphabeticaly, I want to sort the way how I defined the order logic based on their keys. That is possible with orderedDict? – Szocs Arnold Jun 26 '20 at 07:46
  • If your dicts have only one element each, I'd rather use tuples like `('John', 'BMW')`. – bereal Jun 26 '20 at 07:51
  • this is not sorting basically you just want the `key: value` pairs in a specific order. You have to convert your list of dictionaries to a dictionary [here is my try](https://justpaste.it/9gwsf) – sage07 Jun 26 '20 at 07:57
  • I'd use tuples, could you define the code, how would you sort that list? – Szocs Arnold Jun 26 '20 at 07:57
  • 1
    You could use `result = sorted(tuples, key=lambda t: (len(t[0]), t[0]))` to sort the tuples where `tuples = [(k, v) for d in names for k, v in d.items()]`. – hilberts_drinking_problem Jun 26 '20 at 08:24
  • I've provided an answer below that doesn't require tuples or OrderedDicts. – aneroid Jun 26 '20 at 22:58

3 Answers3

0

Similar to Is there a way to sort a list of string by a “predicate” list?: Since names is a list of dictionaries with just one key-value pair each, use the index of the person's name in the order list as the key for the sort:

>>> names = [{'Mark': 'Volvo'}, {'John': 'BMW'}, {'Eliza': 'Merci'}, {'Calen' :'Audi'}]
>>> order = ['John', 'Mark', 'Calen', 'Eliza']
>>>
>>> # with `sorted()`
>>> sorted(names, key=lambda d: order.index(list(d.keys())[0]))
[{'John': 'BMW'}, {'Mark': 'Volvo'}, {'Calen': 'Audi'}, {'Eliza': 'Merci'}]
>>>
>>> # or with `list.sort()`
>>> names.sort(key=lambda d: order.index(list(d.keys())[0]))
>>> names
[{'John': 'BMW'}, {'Mark': 'Volvo'}, {'Calen': 'Audi'}, {'Eliza': 'Merci'}]

dict.keys() is not not subscriptable, so dict.keys()[0] doesn't work. So first convert that to a list and then use its one-and-only key list(dict.keys())[0]. That would give 'Mark', 'John', etc. Then get the index of that person's name in the order list. Note: it will fail if a person is not listed in order.

Even if names is a list of dictionaries with more than one key-value pair each, as long as the person's name is the first key, it will still work as of Python 3.7/3.6. See the note below this item:

Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6.

>>> names = [{'Mark': 'Volvo', 'age': 30},
...          {'John': 'BMW', 'age': 40},
...          {'Eliza': 'Merci', 'age': 50},
...          {'Calen': 'Audi', 'age': 60}]
>>> sorted(names, key=lambda d: order.index(list(d.keys())[0]))
[{'John': 'BMW', 'age': 40}, {'Mark': 'Volvo', 'age': 30}, {'Calen': 'Audi', 'age': 60}, {'Eliza': 'Merci', 'age': 50}]
>>>
aneroid
  • 12,983
  • 3
  • 36
  • 66
-1

First, if your dictionaries only have one entry, tuples seem to be a better choice for this data:

>>> names = [('Mark', 'Volvo'), ('John', 'BMW'), ('Eliza', 'Merci'), ('Calen', 'Audi')]

Now, given this order:

>>> order = ['John', 'Mark', 'Calen', 'Eliza']

you can create a dict that maps the names to the indices:

>>> order_map = { k: v for v, k in enumerate(order) }
>>> order_map
{'John': 0, 'Mark': 1, 'Calen': 2, 'Eliza': 3}

and use it in a key function for sort:

>>> names.sort(key=lambda v: order_map[v[0]])
>>> names
[('John', 'BMW'), ('Mark', 'Volvo'), ('Calen', 'Audi'), ('Eliza', 'Merci')]
bereal
  • 32,519
  • 6
  • 58
  • 104
-1
names = [{'Mark':'Volvo'}, {'John':'BMW'}, {'Eliza':'Merci'}, {'Calen':'Audi'}]
ordered_keys = ['John','Mark','Calen','Eliza']

sorted_names = [name for key in ordered_keys for name in names if key in name]

It iterates over the ordered_keys in order and extracts any name in the list of dict that has that key.