-3

I have 2 dictionaries, dictionary1 is for example ordered as:

{'id': '1234', 'Name': 'John', 'dob': '01/01/2001', 'Address': 'Long Street'}

while dictionary2 is for example ordered as:

{'id': '1235', 'dob': '01/01/2002', 'Address': 'Tower Street', 'Name': 'Michael'}

I need the order of dictionary2 to match that of dictionary1 no matter the name or number of keys as this may change dynamically.

dictionary2 should become:

{'id': '1235', 'Name': 'Michael', 'dob': '01/01/2002', 'Address': 'Tower Street'}

Is there any way to do this? I haven't had any success and neither have I found similar questions.

Thanks a lot!

Adirio
  • 5,040
  • 1
  • 14
  • 26
  • Do they always have the same keys (just in different order)? – superb rain Sep 04 '20 at 10:03
  • Those aren't dictionaries. They're invalid syntax. – superb rain Sep 04 '20 at 10:04
  • 8
    Dictionaries are not ordered data types (although more recent versions of CPython retain an order as an implementation detail). Thinking about the order of a standard dictionary is typically ill-motivated. – John Coleman Sep 04 '20 at 10:05
  • What version of Python? – Steven Rumbalski Sep 04 '20 at 10:06
  • Maybe take a look at OrderedDict? https://docs.python.org/3.8/library/collections.html#collections.OrderedDict – UdonN00dle Sep 04 '20 at 10:07
  • @superbrain Yes they always have the same keys – Matthew Pavia Sep 04 '20 at 10:09
  • @StevenRumbalski Python 3.8 – Matthew Pavia Sep 04 '20 at 10:10
  • I take back part of my comment. It seems that as of Python 3.7 it is no longer an implementation detail (see this)[https://stackoverflow.com/a/57222287/4996248]. I still think that it isn't a good idea to use this newer feature without adequate motivation. – John Coleman Sep 04 '20 at 10:10
  • @JohnColeman The reason for this is that eventually the values of the dictionaries are saved as a CSV row, therefore the order is important – Matthew Pavia Sep 04 '20 at 10:12
  • @MatthewPavia There is a really nice class called `csv.DictWritter` that will order the columns itself, so don't worry about the order for the csv. https://docs.python.org/3/library/csv.html#csv.DictWriter – Adirio Sep 04 '20 at 10:14
  • @MatthewPavia That sounds like it might be adequate motivation. I haven't quite wrapped my mind around this feature and don't fully trust it, but that is mostly since I am used to thinking of dicts as essentially unordered. In any event, it is insertion order, so the only way I see to force the order is to empty one dictionary and insert the elements into it in the desired order. – John Coleman Sep 04 '20 at 10:14
  • Does this answer your question? [How to keep keys/values in same order as declared?](https://stackoverflow.com/questions/1867861/how-to-keep-keys-values-in-same-order-as-declared) – Daniele Grattarola Sep 04 '20 at 10:16
  • Dictionaries in Python 3.6+ maintain the order of key insertion. If you care about the order of the keys you have to create a new dict with the desired order. `d2 = {k: d2[k] for k in d1}` This presumes `d2` and `d1` have the same keys and `d1` has the desired order. – Steven Rumbalski Sep 04 '20 at 10:18

3 Answers3

3

I personally wouldn't do that, and convert the dict to a sequence of tuples, or use OrderedDict instead (if only for it to be explicit).

If you do however insist on doing that and relying on Python 3.7+ semantics of insertion order, this will work:

dict2 = {key: dict2[key] for key in dict1}


You've commented that you're using it to write to csv. If you're using the stdlib's csv module, DictWriter can help.

Otherwise, another option is to extract them as ordered instead of ordering them one by one:

from operator import itemgetter
columns = tuple(dict1.keys())
extract = itemgetter(*columns)
dicts = [dict1, dict2, ...]  # Fill this
for d in dicts:
    values = extract(d)
    # Use values
Bharel
  • 23,672
  • 5
  • 40
  • 80
  • Good answer . "I personally wouldn't do that". Nor would I, but honestly my main reason is that this new feature of Python rubs me the wrong way. It is like an automobile manufacturer telling you that you don't need to wear seat belts anymore. When I see Python code which relies on a dict ordering, it still seems like a code-stink to me, but that is mostly because my code-nose is old. – John Coleman Sep 04 '20 at 10:22
  • @JohnColeman I completely agree with you. That's why I even gave another option which I believe is better, and works by extracting the keys, only relying on a single dict's order. It's easy to modify as well. – Bharel Sep 04 '20 at 10:33
1

Since you said they have the same keys... just use the keys/order of d1 and the corresponding values of d2.

d2 = dict(zip(d1, map(d2.get, d1)))
superb rain
  • 5,300
  • 2
  • 11
  • 25
  • 1
    I didn't downvote you. The code works, but it is less readable that the corresponding dictionary comprehension, which might be the reason that someone did. It is also possible that whoever downvoted you thought that the code didn't work. – John Coleman Sep 04 '20 at 10:32
  • 1
    @JohnColeman I agree, although that answer came only after mine. And I don't think that warrants a downvote. Oh well... – superb rain Sep 04 '20 at 10:35
0

As it has been said, dicts do not guanrantee any kind of order by keys (they may be ordered by insert time depending on what python version you use).

But you can always represent a dict as a list of key-value tuples:

d1 = {'id': '1234', 'Name': 'John', 'dob': '01/01/2001', 'Address': 'Long Street'}
d2 = {'id': '1235', 'dob': '01/01/2002', 'Address': 'Tower Street', 'Name': 'Michael'}

print(sorted(d1.items()))  # [('Address', 'Long Street'), ('Name', 'John'), ('dob', '01/01/2001'), ('id', '1234')]
print(sorted(d2.items()))  # [('Address', 'Tower Street'), ('Name', 'Michael'), ('dob', '01/01/2002'), ('id', '1235')]

You mentioned in a comment that the order was needed to write to a CSV file. In that case, forget about the order. csv.DictWritter allows to write to a CSV file by providing dicts and it will order them according to the columns.

import csv

d1 = {'id': '1234', 'Name': 'John', 'dob': '01/01/2001', 'Address': 'Long Street'}
d2 = {'id': '1235', 'dob': '01/01/2002', 'Address': 'Tower Street', 'Name': 'Michael'}

with open('OUTPUT_FILE.csv', 'w', newline='') as f:
    fieldnames = 'id', 'Name', 'dob', 'Address'
    writer = csv.DictWriter(f, fieldnames=fieldnames)

    writer.writeheader()  # id,Name,dob,Address
    writer.writerow(d1)   # 1234,John,01/01/2001,Long Street
    writer.writerow(d2)   # 1235,Michael,01/01/2002,Tower Street
Adirio
  • 5,040
  • 1
  • 14
  • 26