Posts: 164
Threads: 22
Joined: Feb 2017
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)
Posts: 8,156
Threads: 160
Joined: Sep 2016
# 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
>>>
Posts: 4,784
Threads: 76
Joined: Jan 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) 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
Posts: 164
Threads: 22
Joined: Feb 2017
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)
|