如何对播放列表进行排序,以便相同艺术家的歌曲尽可能分散?
虽然我找不到或计算出来,但我认为有一些快速而简单的方法可以做到这一点,它适用于各种设置以及两个方面:让我们说(un)按艺术家排序这种类型使得另外一种类型几乎总是跟着不同的类型。 (所以这是一个很好的组合)
所以这是一个示例性播放列表:
from collections import namedtuple
Song = namedtuple('Song', ('artist', 'title', 'length'))
# the length is not correct
Mozart_1 = Song('Mozart', 'Don Giovanni', 3.5)
Mozart_2 = Song('Mozart', 'Serenata Notturna', 2.98)
Mozart_3 = Song('Mozart', 'Violin Concerto No. 3 in G, 1st Movement', 8.43)
Bach_1 = Song('Bach', 'Air', 6.18)
Bach_2 = Song('Bach', 'Toccata in D Minor', 12.44)
Beethoven_1 = Song('Beethoven', 'Für Elise', 2.47)
playlist = [Beethoven_1, Mozart_3, Bach_1, Mozart_2, Mozart_1, Bach_2] # unsorted
这将是一个可能的最佳结果:
OPTIMUM = [Mozart_1, Bach_1, Mozart_2, Beethoven_1, Mozart_3, Bach_2]
答案 0 :(得分:5)
我认为这不是一个不合理的答案,可以将可能性分散开来(即使它不符合你的例子):
from collections import defaultdict
from itertools import count
by_artist = defaultdict(count)
new_list = sorted(playlist, key=lambda L: next(by_artist[L.artist]))
给出播放列表:
[Song(artist='Beethoven', title='Fur Elise', length=2.47),
Song(artist='Mozart', title='Violin Concerto No. 3 in G, 1st Movement', length=8.43),
Song(artist='Bach', title='Air', length=6.18),
Song(artist='Mozart', title='Serenata Notturna', length=2.98),
Song(artist='Mozart', title='Don Giovanni', length=3.5),
Song(artist='Bach', title='Toccata in D Minor', length=12.44)]
输出:
[Song(artist='Beethoven', title='Fur Elise', length=2.47),
Song(artist='Mozart', title='Violin Concerto No. 3 in G, 1st Movement', length=8.43),
Song(artist='Bach', title='Air', length=6.18),
Song(artist='Mozart', title='Serenata Notturna', length=2.98),
Song(artist='Bach', title='Toccata in D Minor', length=12.44),
Song(artist='Mozart', title='Don Giovanni', length=3.5)]
答案 1 :(得分:-1)
实际上这个问题的一个答案,我的问题据说是重复的,对我有用。所以,我的问题确实是重复的。虽然如果有人想出一个更快的非随机版本,我仍然会将该答案标记为已接受。这是我的修改版本:
import random
from collections import namedtuple, defaultdict
from operator import attrgetter
Song = namedtuple('Song', ('artist', 'title', 'length'))
# the length is not correct
Mozart_1 = Song('Mozart', 'Don Giovanni', 3.5)
Mozart_2 = Song('Mozart', 'Serenata Notturna', 2.98)
Mozart_3 = Song('Mozart', 'Violin Concerto No. 3 in G, 1st Movement', 8.43)
Bach_1 = Song('Bach', 'Air', 6.18)
Bach_2 = Song('Bach', 'Toccata in D Minor', 12.44)
Beethoven_1 = Song('Beethoven', 'Für Elise', 2.47)
playlist = [Beethoven_1, Mozart_3, Bach_1, Mozart_2, Mozart_1, Bach_2] # unsorted
# one possible optimum
# OPTIMUM = [Mozart_1, Bach_1, Mozart_2, Beethoven_1, Mozart_3, Bach_2]
def optimize(items, quality_function, stop=1000, randrange=random.randrange):
length = len(items)
no_improvement = 0
best = 0
while no_improvement < stop:
i = randrange(length)
j = randrange(length)
copy = items[:]
copy[i], copy[j] = copy[j], copy[i]
q = quality_function(copy)
if q > best:
items, best = copy, q
no_improvement = 0
else:
no_improvement += 1
return items
def quality_maxmindist(items):
s = 0
for item in set(items):
indcs = [i for i in range(len(items)) if items[i] == item]
if len(indcs) > 1:
s += sum(1. / (indcs[i+1] - indcs[i]) for i in range(len(indcs)-1))
return 1. / s
def spread_equal_items_apart(items, key, stop=optimize.__defaults__[0]):
keys, key_to_items = keys_and_key_to_items_dict(items, key)
keys = optimize(keys, quality_maxmindist)
re = []
for k in keys:
re.append(key_to_items[k].pop())
return re
def keys_and_key_to_items_dict(items, key):
key_to_items = defaultdict(list)
keys = []
for i in items:
k = key(i)
keys.append(k)
key_to_items[k].append(i)
return keys, key_to_items
if __name__ == '__main__':
new = spread_equal_items_apart(playlist, attrgetter('artist'))
print(new)
所以new
现在是:
[Song(artist='Mozart', title='Don Giovanni', length=3.5),
Song(artist='Bach', title='Toccata in D Minor', length=12.44),
Song(artist='Beethoven', title='Für Elise', length=2.47),
Song(artist='Mozart', title='Serenata Notturna', length=2.98),
Song(artist='Bach', title='Air', length=6.18),
Song(artist='Mozart', title='Violin Concerto No. 3 in G, 1st Movement', length=8.43)]