Easy way to sort a nested dict - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Easy way to sort a nested dict (/thread-14572.html) |
Easy way to sort a nested dict - Alfalfa - Dec-07-2018 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) RE: Easy way to sort a nested dict - buran - Dec-07-2018 # 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)
RE: Easy way to sort a nested dict - Gribouillis - Dec-07-2018 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)
RE: Easy way to sort a nested dict - Alfalfa - Dec-07-2018 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) |