2014-02-11 43 views
4

如何對播放列表進行排序,以便儘可能擴展相同藝術家的歌曲?在列表中排列元素,以便類似的元素相距最遠

雖然我找不到一個或找出它,但我認爲有一些快速和簡單的方法來做到這一點,這將適用於各種設置,也適用於兩個方面:讓我們說(不)排序藝術家和流派,因此另外一種流派幾乎總是跟着另一種流派。 (所以這是一個很好的組合)

所以這是一個性播放列表:

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

另一個問題不問如何實現多個方面的傳播,這樣是沒有重複的,據我可以告訴。 – Joschua

回答

-1

其實對於這個問題一個答案,我的問題是說是一個重複的,已爲我工作。所以maybie我的問題確實是重複的。雖然如果有人提出了更快的非隨機版本,我仍然會將該答案標記爲已接受。這是我修改的版本:

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)] 
4

認爲這是不是不合理的(即使它不符合你的例子):

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

如果你還添加了一個隨機組件:'next(by_artist [L.artist]),random.random())'你可以在不犧牲擴散的情況下對曲目進行一些混洗。 –

+1

如果你的音樂選擇看起來像我的,有很多藝術家,但有一些明顯過度代表。如果我們有一系列不同藝術家的500首歌曲和莫扎特的500首歌曲,我們是不是最終將在上半年獲得好的藝術家分佈,其中包括莫扎特的作品,其次是499年的莫扎特超級作品? – femtoRgon

+0

@femtoRgon真... lemme認爲... –