MP3 koleksiyonumu sıralamak için bir "nihai karışık" algoritması yazmak istiyorum


33

MP3 dosyalarımı başlık ve sanatçı tekrarını önleyecek şekilde sıralamak için sözde kod önerileri arıyorum . Frank Sinatra, Tony Bennett, Ella Fitzgerald gibi eski standartları söyleyen şarkıları dinliyorum. Her sanatçı aynı şarkıların birçoğunu kaydeder - Beni Aya Aya Uçur, Bu Gece Baktığınız Yol, Stardust vs. Eğer 2000 şarkım varsa ve 20'si Ella ise, onu her 100 şarkıda bir kez duymak isterim. 10 sanatçı şarkı söylerse Fly Me To The Moon şarkılarını her 200 şarkıda da duymak isterim. Tabii ki "nihai karıştırmam" ı oluşturmak için bu iki gereksinimi birleştirmek istiyorum.

Bunun oldukça geniş bir soru olduğunu biliyorum. Programlamaya henüz başlamadım, bu yüzden almam gereken iyi bir yaklaşımın önerilerini arıyorum. Aslında diğer şarkı özniteliklerini eşit aralıklarla yerleştirmekle ilgili başka gereksinimlerim var ancak bu konuya girmeyeceğim.


Başlangıç ​​noktası olarak kod değiştiriyorum, mp3 dosyalarını değiştirmek ve ID3 etiketlerini okumak için burada buldum .

Aşağıdaki parsifal'in cevabını kullanarak ihtiyacımı karşılayan küçük bir uygulama yazdım. Ayrıca buraya bir takip sorusu da yazdım . Tüm büyük tepkiler için teşekkürler!


3
Harika bir soru, harika bir problem, algoritmaları gerçekten iyi bilen biri, sizin için resmi yöntemleri temel alan büyük bir cevaba sahip olacaktır.
Jimmy Hoffa

Yani, müzik koleksiyonunuzun% 50'si aynı sanatçıdan geliyorsa, sanatçıyı her iki şarkıda da dinlemek istersiniz, başka ne kadar sanatçı olduğuna bakılmaksızın ... Belki% 50 kadar olmasa da fikir. Belki de sadece benim düşüncem, ama her sanatçıdan aynı miktarda şarkıya sahip olmadığınız sürece, bu bir "nihai karışık" gibi gelmiyor. Öte yandan, bir sanatçının yalnızca 1 şarkısı varsa, bunun çok fazla çalmasını istemezsin. 2 arasında bir denge bulmak zor olmamalıdır.
Dukeling

Sadece bu sözde kod gibi bir şey yapardım: while (length(songs) > 0) { x := rand(); addElem(shuffle, songs[x]); remElem(songs, x); }ama siz "nihai bir karıştırma" istediğinizi söylüyorsunuz. Bununla gerçekten ne istediğini bilmiyorum, soruyu okumak bile ...
Cole Johnson

şarkı listenizi bir yere yükleyebilir misiniz - başlık ve sanatçılar sekmesi veya boru ayrılmış veya XML
tgkprog

Banshee'de (bir eklenti veya çekirdek olarak) olması güzel olurdu!
phw

Yanıtlar:


5

Programınızı bir kez çalıştırmak ve bir çalma listesi oluşturmak mı yoksa bir sonraki şarkıyı canlı mı seçmek istiyorsunuz?

İkincisi, o zaman cevap basit:

  • Tüm şarkılarınızı, sanatçı ve unvanı içeren bir dizi oluşturun.
  • Son çalınan şarkıların başlıkları için bir liste (tercih edilen bağlantı listesi) oluşturun. Bu liste boş başlar ve bir şarkıyı her çaldığınızda listeye eklersiniz. Liste istediğiniz "şarkı tekrarlanmıyor" boyutuna ulaştığında, en eski (ilk) girişi bırakın.
  • Bir sanatçı listesi için aynen.

Bir şarkı seçmek daha sonra aşağıdaki adımlar dizisine dönüşür:

  1. "Tüm şarkılar" dizisinden rastgele bir şarkı seçin. Bu sadece 0 ile dizinin büyüklüğü arasında rastgele bir sayıdır.
  2. Bu şarkının zaten çalınan şarkılar listesinde olup olmadığını görün. Öyleyse, adım 1'e geri dönün.
  3. Sanatçının zaten çalınan sanatçı listesinde olup olmadığına bakın. Öyleyse, adım 1'e geri dönün.
  4. Gerekirse eski girişleri bırakarak şarkı sanatçısı / unvanını uygun listelere ekleyin.
  5. Şarkıyı çal.

Birkaç olası sorun var, ancak bunu ev ödevi olarak yapıyor olmanız ve gerçek bir proje olmanızın önemi yoktur.

  • @Dukeling'in bir yorumda dediği gibi, koleksiyonunuz tek bir sanatçı veya şarkı adı lehine önemli ölçüde dengesizse, şarkıları sürekli olarak reddettiğiniz bir döngüye girebilirsiniz. Uygulamada, bu bir sorun olmayacak. Çözüm, "zaten görülmüş" listelerin boyutunu azaltmanız gerektiğidir. Ve # 2 ve # 3 numaralı adımlara sayaç eklemek sorun olup olmadığını söyleyebilir (arka arkaya 10 hata görürseniz, bir uyarı verin ve / veya listenin boyutunu azaltın).
  • Yalnızca bir kez çalınan şarkılarınızı içeren bir çalma listesi oluşturmaya çalışıyorsanız, şarkıları kaynak diziden kaldırmanız gerekir. Bu aynı zamanda çok fazla "yakın zamanda oynanan" başarısızlıkla nasıl başa çıkacağınızı da değiştirecektir (çünkü sonunda kaynak dizinizde yalnızca bir sanatçıyla karşılaşabilirsiniz).
  • ID3 etiketleriniz benimkine benziyorsa, çok fazla yazım hatası var. "Duke Ellington" ın "Duke Elingten" den farklı olması gerekiyor mu? Eğer evet ise, o zaman "son çalınan" listeleri tararken bir Levenstein eşleştirici kullanmaya bakın.

RockBox ( rockbox.org ) kullanıyorum. Herhangi bir şarkı klasörü için dinamik bir çalma listesi oluşturabilir (ayrıca kaydedilebilir ve yer imlerine eklenebilir). Her şarkının başlığını 0001, 0002 olarak eklemeyi planlıyorum, sonra da bu sırayla çalıyorum.
GeliştiriciDan

@DeveloperDan - aynı işlem işe yarıyor, fakat en sonunda not ettiğim gibi kurallara uymayan şarkılarınız olacak. İki seçeneğiniz var: kuralları uyarlayın ve tekrar çalıştırın veya (çok sayıda yoksa) şarkıları rastgele ekleyin.
parsifal

1. adımda bir liste oluşturur ve 2 ve 3'te çıkarırdım. Bu, bir döngüye takılmanızı imkansız hale getirir ve liste boşalırsa, kuralları değiştirmeniz ve yeniden taramanız gerektiğini biliyorsunuzdur. Bunu yapmanın daha sağlam bir yolu.
Macke

13

Bir jeneratör kullanmadan önce böyle bir şey yaptım (C # 'da, yieldher döngü yinelemede sonsuz bir döngü ). Her bir yineleme, şarkı havuzuna (ya da her neyse) bakar ve çok yakın zamanda çalınanları (ya da olumsuz kriterleri) atar. Ardından filtrelenen listeden birini seçip durumunuzu güncelleyin. Devletiniz sürüklenirken (Sinatra olmayan şarkılar çalıyorsunuz) kriterler bozuluyor ve hariç tutulan şarkılar yeniden eklenmeye başlıyor.

Tabii ki uğraşılacak köşe davaları var:

  • Bütün şarkıları atarsan ne olur? (genellikle devleti istikrarsızlaştırmayı ümit ederek rastgele birini seçer)
  • Bazı kriterler tercih edilmeli mi? (genellikle durum, belki de Beni Ay'a arka arkaya uçmak oynamak istemezsiniz ve Sinatra'yı arka arkaya çalmamayı tercih edersiniz, ama eğer sahip olduğunuz buysa ...)
  • Şarkı koleksiyonunuz kavga sırasında güncellenirse ne olur? (genellikle başa çıkmak kolay, ancak eşzamanlılık kullanıma bağlı olarak sorunlar olabilir)

11

Telastyn'in ortaya attığı sorunun dışlayıcılarını yok sayarak, sırt çantası probleminde bir çeşitlilik varmış gibi geliyor . Neyse ki, oldukça iyi belgelenmiş bir algoritma.

Vikipedi'den

Her biri ağırlığa ve değere sahip olan bir ürün kümesi göz önüne alındığında, toplam ağırlığın verilen bir limitin altında veya ona eşit olması ve toplam değerin mümkün olduğu kadar büyük olması için bir koleksiyona dahil edilecek her maddenin sayısını belirleyin.

Ek bir sırt çantası problemleri listesi ile birlikte, bu makalede listelenen bazı potansiyel olarak varyasyonlar vardır


Sırt çantası probleminin bir varyasyonu çok amaçlı sırt çantası problemidir. karınca kolonisi algoritması bu sorunu çözme aracı olarak önerilir. Karınca kolonisi yaklaşımı, sorunuzun NP zorluğundan kaçınmanız için en kolay yol olabilir.

Sorunu seyahat eden satıcı probleminin aşırı bir değişkeni olarak görmeyi de görebiliyordum . Ziyaret edilecek her şehir gerçekten çalınmasını istediğiniz bir şarkı ama sanatçılar arasındaki aralıkları nasıl belirleyeceğinizden emin değilim. Bu öneri aynı zamanda ant kolonisi yaklaşımı ile de ilgilidir / çözülebilir.


8

Bunun “burada benim kütüphanem, bu programı çalıştır ve şarkıları çalmak için bir düzen oluştur” olduğu varsayımı altında çalışıyorum.

Bu uygulanmadı ve karıştırılmasının ne kadar iyi olacağına emin değilim. Ben biraz olduğumu olabilir çok şarkılardan oluşan ilk kurulum verilen kalanı için öngörülen sırayla neden olur filtre, (sanırım) sıkı.

Birinde ideal_gapkarma var. Bu, belirli bir özelliği olan bir şarkının yoğunluğu ile hesaplanır (sanatçı, albüm, başlık). Birinin 2000 şarkısı varsa ve bunlardan 20'si Ella adında bir sanatçıya aitse ideal_gap{'artist'}{"ella"}100 olur.

Bu bilgiye sahip olmak aynı zamanda ideal_gap değerlerinin maksimumuna sahiptir. Bunu arayalım max_gap.

Şunu düşünün: ideal_gapSadece iki sanatçının daha sonra diğer şarkının 1000 şarkı çalmasını engellediği bir şarkının önlenmesini önlemek için en yüksek değere sahip olun ve ayrıca "geri dönme, şarkı yok, birçok tekrarlama" ile sonuçlanan max_gap değerini büyük ölçüde arttırın kapalı, şarkı yok ".

En son çalınan max_gap şarkıların incelenmesi (bu önceki bir çalışmayla doldurulabilir, böylece Frank Sinatra'nın Fly Me To the Moon şarkısıyla bitmesi durumunda, bir sonraki şarkı aynı şarkı ile şans eseri başlamaz). Bir takım aday şarkılarıyla sonuçlanan kütüphane. Bir şarkı ancak aday şarkılardaki tüm boşlukları ideal_gapbu özelliklerden daha azsa olacaktır .

Aday şarkı kümesinden rastgele birini seçin.

Şunu düşünün: setin ağırlıklandırılması, böylece daha yüksek bir maksimum aralığa sahip olan şarkılar daha muhtemel olacak şekilde ağırlıklandırılır. Bu şekilde, bir çalma listesinin sonunda biriken daha büyük maksimum boşluk şarkıları bulunmaz.

Şunu düşünün: Üç özelliğin de ideal boşluktan daha büyük olması yerine, üçte ikisinden ikisi. Bu, bir şeyin ideal idealden daha erken çalınabileceği anlamına gelebilir, ancak "şarkıyı rastgele seç" seçeneğinin daha fazla seçeneğe sahip olduğu anlamına gelen aday şarkı setinin boyutunu artırır.

Geri çekil gereksinimleri doldurmak hiçbir şarkı varsa max_gap1 ile, ve bütün ideal_gaps n/max_gapyüzde nereye nbu geri çekilmenin olmuştur sayısıdır. Bu yolla, eğer max_gap100'lük bir sayı varsa ve bu yinelemede 5 kez geri çekildiyse, 100'lük bir ideal_gap geçici olarak 95'e, 20'lik bir ideal_gap geçici olarak 19'lu olacak şekilde ayarlandı. en az bir aday şarkı olana kadar ara verin ve ardından yukarıdaki gibi seçin.

Bir düşünün: minimum havuz büyüklüğüne sahip. Bu, varyansa eklenir, ancak çalınabilecek başka bir şarkı olduğunda, bir şarkının ideal boşluktan daha erken çalınmasına neden olabilir.


1

Bu bir optimizasyon işi ve en uygun çözümü arıyorsanız oldukça karmaşık bir iştir . Neyse ki, yeterince iyi olacağı bu vakalardan biri olduğuna inanıyorum.

Yapılacak ilk şey, matematiksel bir kalite kriteri oluşturmaktır; bu, listenin permütasyonu verilen, permütasyonun ne kadar iyi veya kötü olduğunu tanımlayan tek bir sayı getirecek bir formüldür.

Basit bir formül önerisi, dikkate almak istediğiniz her bir kritere bir ağırlık verilmelidir, önemli kriterlere yüksek ağırlık vermeli ve birçok şarkının aynı özelliği paylaştığı ölçütlere düşük ağırlık verilmelidir. :

For each song on the list
    For each other song on the list
        For each criteria
            If the two songs share that criteria
                Add to the quality value: square root( [criteria weight]/[distance between the two songs] )

Bu prosedürün ürettiği değer ne kadar düşük olursa, liste müsaadesi o kadar iyidir.

Permütasyon yapmak

Şimdi bu formülü math.stackexchange'e götürebilir ve çok sayıda şarkı dışında her şey için en uygun çözümü bulmanın ne kadar zor ve büyük olasılıkla pratik olarak imkansız olduğunu söylemelerini sağlayabilirsiniz, ya da sadece saat döngüleri atabilir ve güzel çözüm.

Bunu yapmanın birçok yolu var, işte bir tane:

Start with a random permutation of the list.
Several million times do the following:
    Select two entries at random
    For each of those two entries calculate their contribution to the quality value
    Swap the positions of the two entries
    Calculate the contribution to the quality value of the two entries at their new position
    If the sum of the calculations in the new positions is greater than the sum in the old positions
        Swap back

Bu biraz israf algoritmasıdır, ancak tek bir arzu kadar çok kritere uyması ve uygulaması kolaydır.

optimizasyonları

Farklı tweaks ve optimizasyonların yükleri uygulanabilir, işte birkaçı:

Kalite değeri hesaplamasında, bir şarkıyı listedeki diğer şarkılara karşı kontrol etmeyin, bunun yerine sadece 100 ya da daha yakın şarkıya karşı kontrol edin. Yaygın değerler için bu hız optimizasyonunun sonucun kalitesi üzerinde pratik olarak etkisi yoktur.

Belirli bir özelliğin nadir bir değeri için, bu değerin mevcut örneklerini izlemek, onları aramaktan daha etkili olabilir.

Çok az sayıda örneği olan değerlerin eşit aralıklarla yerleştirilmesinin önemli olduğunu düşünüyorsanız, bu belirli değerlerin ağırlığını arttırmanız gerekir, ancak o kriterin diğer değerleri için gerekli değildir.

Listedeki tüm olası çiftleri eşit dağılımda seçen sözde rasgele bir fonksiyon, toplama başına normal bir rasgele seçimden biraz daha iyi bir verime sahip olabilir.


Algoritmik hale getirmenin , daha fazla incelemek için bir yer olabilecek bir taklit tavlama şekli olduğuna inanıyorum .

@MichaelT Hayır, simüle edilmiş tavlama, yerel bir maksimumda yakalanmamak için daha düşük bir duruma gerilemesine izin veren bir "sıcaklık" kullanır. Bu sadece yerel bir arama , benzetilmiş tavlama veya herhangi bir diğer olası arama algoritmalarından herhangi biri ile nispeten kolay bir şekilde değiştirilebilir, ancak buna çok fazla ihtiyaç olduğunu sanmıyorum. Temel olarak, diğer tüm algoritmaların farklı şekilde yaptığı, yerel maksimayı önlemekten kaçınmaktır, ancak kabul edilebilir bir çözüm olmayan bu sorun için yerel bir maksimye bulacağınızı sanmıyorum.
aaaaaaaaaaaa

0

İnsanların farklı yaklaşımlar alması ilginç. Aşağıdakileri yapardım:

Şimdiye kadar oynanan tüm parçalara dayanarak, her birine bir puan verin. En düşük skorla parçayı çalın (veya aynı skorlar durumunda, en düşük skorla eşleşen rastgele bir not). Tekrar et.

Zor olan bit, elbette bir puan veriyor. Bundan sonra oynayabileceğiniz her olası parça için, daha önce çalmış olduğunuz her (veya sınırlı sayıda) parçadan geçmeniz gerekir. [Mümkün olan sonraki] parça ve [yakın zamanda çalınan] parça ortak bir şeye sahipse, ne kadar ortak noktaya sahip olduklarına, ne ortak noktaya sahip olduklarına ve [en son çalınan] parçanın ne kadar zaman önce olduğuna bağlı olarak puan ekleyin oynadı. Muhtemelen "hiçbir şekilde ortak hiçbir şeyin" 0 olmasını istemezsiniz, böylece tüm parçalarla 0 olarak başlayabilirsiniz.

Muhtemelen, el yapımı çalma listelerini denemek isteyip, matematiği doğru yapmak için denemek isteyeceksiniz - ortak kullanılan kelimelerin sayısını veya ortak kullanılan kelimelerin karesini veya sayının karekökünü mü istiyorsunuz? Ortak kelimeler Tüm çalma listenizi gözden geçirin, hangisinin üst sıralarda yer aldığını görün ve dengeyi düzeltmek için faktörleri elle ayarlayın. Belki mektup başına gitmek istersen, "Duke Ellington", "Duke Elington" ile karşılaştırıldığında daha yüksek bir puan aldı, ama "King Elle Duton" ile karşılaştırıldığında daha yüksek bir puan aldı (eğer hiç mektup kaybetmediysem :) . Hangi alanları karşılaştırmak istediğinizi ve alanlar arasında karşılaştırmak isteyip istemediğinizi çok dikkatli düşünmelisiniz. İki parçayı bile düşünebilirsiniz (harf çiftleri; Duke ellington, "Du", "

Çok fazla sayıda belirli bir sanatçıya sahipseniz, o sanatçının öncelikli olarak bırakılabileceğini unutmayın - Duke Ellington şarkılarınızın 10'unu da dinlemeden önce, 5 defa benzersiz bir sanatçının bir parçasını duyabilirsiniz. İstediğiniz bu olabilir veya olmayabilir. Karşılaştıracağınız her şeyin bir sözlüğünü ve ne sıklıkta ortaya çıktığını belirleyerek bundan kaçınabilirsiniz, bu yüzden çok sayıda Duke Ellington parçanız varsa, Duke Ellington'a ait iki parça Billy Joe Shaver'ın iki tanesinden "daha az benzer" olur. .

Her iki çift şarkı birleşiminde bir masayı önceden hazırlamaya bile değer olabilir. Ayrıca, bir sonraki hangi şarkının çalınacağını düşünürken, şu ana kadarki en iyi şarkıyı hatırlaman yeterli; dikkate alınacak bir sonraki şimdiye kadarki en iyi şarkıdan daha kötü bir puan aldıysa, bir sonrakine geçebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.