Python Forum
Easy way to sort a nested dict
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Easy way to sort a nested dict
#1
I want to convert a dict of audio metadata into an ordered dict, sorted by it's nested values (such as values of keys 'artist' or 'track'). What would be the fastest way to achieve this?

The database is organized like this:

#!/usr/bin/python3
from collections import OrderedDict

db = \
{
  "/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-17 Disc Wars.mp3": {
    "duration": "00:04:11",
    "artist": "Daft Punk",
    "album": "Tron: Legacy (Cd1)",
    "track": "17",
    "title": "Disc Wars"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/07 - Godichons.mp3": {
    "duration": "00:05:09",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "7",
    "title": "Godichons"
  },
  "/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-07 Rinzler.mp3": {
    "duration": "00:02:17",
    "artist": "Daft Punk",
    "album": "Tron: Legacy (Cd1)",
    "track": "07",
    "title": "Rinzler"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/10 - Le Tape.mp3": {
    "duration": "00:06:06",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "10",
    "title": "Le Tape"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/09 - L'or.mp3": {
    "duration": "00:05:05",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "9",
    "title": "L'or"
  }
}

db = OrderedDict(sorted(db.items(), key=lambda t: t[0]))
for key in db:
    print(key)
Reply
#2
# Create an object to compute John's weight in Kgs as well as age in years
from collections import OrderedDict
 
db = {
  "/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-17 Disc Wars.mp3": {
    "duration": "00:04:11",
    "artist": "Daft Punk",
    "album": "Tron: Legacy (Cd1)",
    "track": "17",
    "title": "Disc Wars"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/07 - Godichons.mp3": {
    "duration": "00:05:09",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "7",
    "title": "Godichons"
  },
  "/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-07 Rinzler.mp3": {
    "duration": "00:02:17",
    "artist": "Daft Punk",
    "album": "Tron: Legacy (Cd1)",
    "track": "07",
    "title": "Rinzler"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/10 - Le Tape.mp3": {
    "duration": "00:06:06",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "10",
    "title": "Le Tape"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/09 - L'or.mp3": {
    "duration": "00:05:05",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "9",
    "title": "L'or"
  }
}
 
db = OrderedDict(sorted(db.items(), key=lambda item:(item[1]['artist'], '{:0>2}'.format(item[1]['track']))))
for key in db:
    print(key)
Output:
/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-07 Rinzler.mp3 /data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-17 Disc Wars.mp3 /data/Music/Keith Kouna/Les annees monsieur/07 - Godichons.mp3 /data/Music/Keith Kouna/Les annees monsieur/09 - L'or.mp3 /data/Music/Keith Kouna/Les annees monsieur/10 - Le Tape.mp3 >>>
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#3
Buran's idea is very good. Here is a variation with some abstraction
#!/usr/bin/python3
from collections import OrderedDict
 
db = \
{
  "/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-17 Disc Wars.mp3": {
    "duration": "00:04:11",
    "artist": "Daft Punk",
    "album": "Tron: Legacy (Cd1)",
    "track": "17",
    "title": "Disc Wars"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/07 - Godichons.mp3": {
    "duration": "00:05:09",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "7",
    "title": "Godichons"
  },
  "/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-07 Rinzler.mp3": {
    "duration": "00:02:17",
    "artist": "Daft Punk",
    "album": "Tron: Legacy (Cd1)",
    "track": "07",
    "title": "Rinzler"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/10 - Le Tape.mp3": {
    "duration": "00:06:06",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "10",
    "title": "Le Tape"
  },
  "/data/Music/Keith Kouna/Les ann\u00e9es monsieur/09 - L'or.mp3": {
    "duration": "00:05:05",
    "artist": "Keith Kouna",
    "album": "Les ann\u00e9es monsieur",
    "track": "9",
    "title": "L'or"
  }
}
  
from functools import wraps

def dbsorter(func):
    @wraps(func)
    def wrapper(db, reverse=False):
        return OrderedDict(sorted(
            db.items(), reverse=bool(reverse), key=lambda item: func(*item)))
    return wrapper

@dbsorter
def by_artist_and_track(key, data):
    return data['artist'], int(data['track'])

sdb = by_artist_and_track(db)
for key in sdb:
    print(key)
print()

@dbsorter
def by_duration(key, data):
    h, m, s = (int(x) for x in data['duration'].split(':'))
    return (h, m, s)

sdb = by_duration(db, reverse=True)
for key in sdb:
    print(key)
Output:
/data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-07 Rinzler.mp3 /data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-17 Disc Wars.mp3 /data/Music/Keith Kouna/Les années monsieur/07 - Godichons.mp3 /data/Music/Keith Kouna/Les années monsieur/09 - L'or.mp3 /data/Music/Keith Kouna/Les années monsieur/10 - Le Tape.mp3 /data/Music/Keith Kouna/Les années monsieur/10 - Le Tape.mp3 /data/Music/Keith Kouna/Les années monsieur/07 - Godichons.mp3 /data/Music/Keith Kouna/Les années monsieur/09 - L'or.mp3 /data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-17 Disc Wars.mp3 /data/Music/Daft Punk/Tron_ Legacy (Cd1)/1-07 Rinzler.mp3
Reply
#4
Thanks to both of you. I forgot to mention that the sort parameter (artist, album, ...) and the sort order must be dynamically callables. Also, track can be an empty string "" and duration "?".

So I endend up doing it like this:

def _sortInt(string):
    try:
        if string.count(":"):
            string = string.split(":")
            return int(string[0])*3600 + int(string[1])*60 + int(string[2])
        else:
            return int(string)
    except ValueError:
        return 0

def _sortMetadata(db, column, reverse):
    if column == "track" or column == "duration":
        return OrderedDict(sorted(db.items(), key=lambda item:(_sortInt(item[1][column])), reverse=reverse))
    else:
        return OrderedDict(sorted(db.items(), key=lambda item:(item[1][column]), reverse=reverse))

db = _sortMetadata(db, "track", reverse=False)
db = _sortMetadata(db, "album", reverse=False)
db = _sortMetadata(db, "artist", reverse=False)
#db = _sortMetadata(db, "duration", reverse=False)
for key in db:
    print(key)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Photo a.sort() == b.sort() all the time 3lnyn0 1 1,277 Apr-19-2022, 06:50 PM
Last Post: Gribouillis
  Updating nested dict list keys tbaror 2 1,243 Feb-09-2022, 09:37 AM
Last Post: tbaror
  changing key names in nested dict wardancer84 6 2,095 Sep-10-2021, 08:13 AM
Last Post: wardancer84
Star Recursively convert nested dicts to dict subclass Alfalfa 1 2,839 Jan-22-2021, 05:43 AM
Last Post: buran
  [nested dics] Easy way to find if a key exists? Winfried 9 2,891 Sep-17-2020, 05:30 PM
Last Post: deanhystad
  Sort a dict in dict cherry_cherry 4 62,386 Apr-08-2020, 12:25 PM
Last Post: perfringo
  convert List of Dicts into a 2 deep Nested Dict rethink 1 3,156 Aug-23-2019, 05:28 PM
Last Post: ichabod801
  How can I sort my dict ? Mike Ru 1 1,781 Feb-16-2019, 11:50 PM
Last Post: ichabod801
  how to create a nested dict.. wardancer84 5 3,613 Nov-23-2018, 04:01 AM
Last Post: Larz60+
  sorting nested dict according to values merlem 6 17,467 Apr-01-2017, 10:01 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020