Je cherche des suggestions de pseudocode pour triant mes fichiers MP3 d'une manière qui évite la répétition de titre et d'artiste . J'écoute Crooners - Frank Sinatra, Tony Bennett, Ella Fitzgerald, etc., chantant d'anciennes normes. Chaque artiste enregistre de nombreuses mêmes chansons - volez-moi sur la lune, la façon dont vous regardez ce soir, Stardust, etc. Mon objectif est d'organiser les chansons (ou de commander la liste de lecture) avec l'espace maximum entre les artistes et les titres de la chanson. Donc, si j'ai 2000 chansons et 20 sont ella, j'aimerais l'entendre une seule fois sur 100 chansons. Si 10 artistes chantent me voler sur la lune, j'aimerais l'entendre une fois dans 200 chansons. Bien sûr, je souhaite combiner ces deux exigences pour créer mon "sulfle ultime".
Je sais que c'est une question ouverte assez large. Je n'ai pas encore commencé à la programmer, alors je cherche juste des suggestions d'une bonne approche à prendre. En fait, j'ai d'autres exigences concernant un compromis d'espacement uniformément d'autres attributs de chansons, mais je ne vais pas entrer dans cela ici.
Comme point de départ, je modifie le code I trouvé ici pour manipuler des fichiers MP3 et lire des balises ID3.
J'ai écrit une petite application qui satisfait à mes besoins en utilisant la réponse de Parsifal ci-dessous. J'ai aussi écrit un suivi question ici . Merci pour toutes les grandes réponses!
Voulez-vous exécuter votre programme une fois et générer une playlist ou choisir la prochaine chanson en direct?
Si ce dernier, la réponse est simple:
Choisir une chanson devient alors la séquence suivante des étapes:
Il y a quelques problèmes possibles, mais ils ne devraient compter que si vous faites cela comme devoirs et non un véritable projet.
J'ai fait quelque chose comme ça avant d'utiliser un générateur (en C #, une boucle infinie que yield
s chaque itération de boucle). Chaque itération regarde sa piscine de chansons (ou autre) et jette des celles qui ont été jouées trop récemment (ou quels que soient les critères négatifs). Ensuite, vous en choisissez une dans la liste filtrée et mettez à jour votre état. Lorsque votre état dérive (vous jouez des chansons non-Sinatra), les critères tombent en panne et que vos chansons exclues commencent à être réinvesties.
Bien sûr, il y a des cas d'angle de faire face à:
Ignorer les valeurs aberrantes de votre question que Telastyn apporte, il semble que vous ayez une variation sur le problème du knapack . Heureusement, c'est un algorithme assez bien documenté.
De Wikipedia
Compte tenu d'un ensemble d'éléments, chacun d'un poids et d'une valeur, déterminez le nombre de chaque élément à inclure dans une collection de sorte que le poids total est inférieur ou égal à une limite donnée et la valeur totale est aussi importante que possible.
Il existe certaines variations potentiellement pertinentes énumérées dans cet article avec une liste supplémentaire de problèmes de bande de bande
Une variation du problème du knapsack est le problème du knapack multi-objectifs. L'algorithme de la colonie d'ant est suggéré comme moyen de résoudre ce problème. L'approche de la colonie des fourmis pourrait être le moyen le plus simple d'éviter les aspects du NP-dur de votre question.
Je pourrais aussi voir que votre problème est une variante extrême du vendeur de voyage . Chaque ville à visiter est vraiment une chanson que vous voulez jouer, mais je ne sais pas comment vous spécifierez les intervalles entre artistes. Cette suggestion est également liée à/peut être résolue par l'approche de la colonie des fourmis.
Je travaille sous l'hypothèse selon laquelle c'est une "Voici ma bibliothèque, gère ce programme et génère une commande pour jouer les chansons".
Cela n'a pas été mis en œuvre et je suis incertain à quel point cela préformera son mélange. C'est peut-être que je suis un peu TOO strict dans le filtre, ce qui résulterait (je crois) dans un ordre prescrit pour le reste donné à un premier ensemble de chansons.
On a un ideal_gap
hachage. Ceci est calculé par la densité d'une chanson avec une propriété donnée (artiste, album, titre). Si l'un a 2 000 chansons et 20 d'entre eux sont par un artiste nommé Ella, le ideal_gap{'artist'}{"ella"}
serait 100.
Avoir cette information, on dispose également du max des valeurs idéales_gap. Permet d'appeler ceci max_gap
.
Considérer: avoir un maximum pour le ideal_gap
Valeur pour empêcher une chanson que seuls deux artistes ont chanté de la prévention de l'autre chanson d'être joué 1000 chansons plus tard et d'augmenter considérablement la valeur max_gap entraînant de nombreuses itérations de "Back off, pas de chansons" .
Examiner les dernières chansons max_gap jouées (cela peut être renseigné à partir d'une exécution précédente de sorte que s'il finit avec Frank Sinatra chantant me voler sur la lune, la prochaine course ne commencera pas avec la même chanson par hasard), on filtre des chansons de la bibliothèque donnant lieu à un ensemble de chansons candidates. Une chanson ne serait que dans les chansons candidates si toutes ses lacunes sont inférieures à la ideal_gap
Pour ces propriétés.
Depuis l'ensemble des chansons candidates, sélectionnez-en un au hasard.
Considérez: Pondération de l'ensemble afin que les chansons qui attribuent une fossée maximale supérieure sont pondérées comme plus probables. De cette façon, on n'a pas toutes les plus grandes chansons de gap Max accumulées à la fin de la playlist.
Considérons: au lieu d'avoir les trois propriétés étant supérieures à l'écart idéal, deux sur trois. Cela peut signifier que quelque chose pourrait être joué plus tôt que l'idéal idéal, mais augmente la taille de l'ensemble de la chanson candidate Signification signifie "Sélectionnez-en au hasard" avec plus d'options.
S'il n'y a pas de chansons qui remplissent les exigences, renvoyez le max_gap
par 1, et tous idéal_gaps par n/max_gap
Pourcentage où n
est le nombre de fois que cela a été renvoyé. De cette façon s'il y a un max_gap
de 100, et il a été sauvegardé 5 fois dans cette itération, un effet idéal_gap de 100 serait ajusté pour être temporairement 95, et une valeur idéale de 20 serait ajustée pour être temporairement 19. Répétez la recul de l'espace jusqu'à ce qu'il soit au moins une chanson candidate, puis le sélectionnez comme ci-dessus.
Considérez: avoir une taille minimale de la piscine. Cela ajoute à la variance, mais peut entraîner une chanson jouée plus tôt que l'écart idéal lorsqu'il y a une autre chanson qui pourrait être jouée.
Ceci est un travail d'optimisation et un assez complexe si vous recherchez la Solution optimale. Heureusement, je crois que c'est l'un de ces cas où suffisamment bien.
La première chose à faire est d'établir un critère de qualité mathématique, c'est-à-dire une formule qui étant donné une permutation de la liste rendra un nombre unique décrivant la qualité ou la mauvaise mise en permanence.
Une simple suggestion de formule, chaque critère que vous voudriez prendre en compte doit avoir un poids, donner un poids élevé à des critères importants et un poids faible aux critères où beaucoup de chansons partagent la même propriété, de sorte que celles ne dominent pas :
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] )
La valeur inférieure de cette procédure produise, meilleure est la permutation de la liste.
Maintenant, vous pourriez prendre cette formule à Math.StaCkExchange et vous dire à quel point c'est incroyablement difficile et éventuellement impossible, il est de trouver la solution optimale pour tout sauf un nombre trivial de chansons, ou vous pouvez simplement lancer des cycles d'horloge et obtenir une bonne solution.
Il y a beaucoup de façons de faire cela, voici un:
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
C'est un algorithme quelque peu inutile, mais il est facile à mettre en œuvre et peut traiter autant de critères qu'un désir.
Des charges de modifications et d'optimisations différents peuvent être appliquées, voici quelques-uns:
Dans le calcul de la valeur de qualité, ne vous inquiétez pas de vérifier une chanson contre toutes les autres chansons de la liste, ce qui suffit à le vérifier contre les chansons de 100 ou plus les plus proches. Pour les valeurs communes Cette optimisation de la vitesse n'a pratiquement aucune influence sur la qualité du résultat.
Pour une valeur rare d'un bien donné, il peut être plus efficace de suivre les instances existantes de cette valeur que de les rechercher.
Si vous pensez qu'il est important que les valeurs qui ont peu d'instances soient espacées de même, plutôt que de loin, il est probablement nécessaire d'augmenter le poids de ces valeurs spécifiques, mais pas pour d'autres valeurs de ce critère.
Une fonction pseudo-aléatoire qui choisit toutes les paires possibles de la liste dans une distribution égale peut avoir une efficacité légèrement meilleure par choix qu'un choix aléatoire normal.
C'est intéressant quelles différentes approches prennent les gens. Je ferais ce qui suit:
Basé sur toutes les pistes jouées jusqu'à présent, donnez à chacun un score. Jouez sur la piste avec le score le plus bas (ou, dans le cas de scores identiques, un aspect aléatoire correspondant au score le plus bas). Répéter.
Bien sûr, le bit difficile donne un score. Pour chaque piste possible, vous pourriez jouer ensuite, vous devrez passer par chaque (ou un nombre limité de) que vous avez déjà joué. Si la piste [Possible suivante] et la piste [récemment jouée] ont quelque chose en commun, vous ajoutez au score, en fonction de leur nombre en commun, de ce qu'ils ont en commun et de la fréquentation [récemment jouée]. joué. Vous voudriez probablement que "rien du tout en commun" soit 0, vous pouvez donc commencer avec toutes les pistes comme 0.
Vous voudrez probablement expérimenter des listes de lecture fabriquées à la main pour commencer, pour obtenir les mathématiques à droite - voulez-vous le nombre de mots en commun, ou le carré du nombre de mots en commun, ou la racine carrée du nombre des mots en commun? Exécutez toute votre playlist à travers, voyez ceux qui flottent au sommet comme étant "le plus commun" et modifient à la main les facteurs pour obtenir le bon équilibre. Peut-être que vous voulez aller par lettre, alors "Duke Ellington" a un score élevé par rapport à "Duke Elington", mais un score encore plus élevé par rapport au "roi d'elle Duton" (si je n'ai perdu aucune lettre :) . Vous devriez considérer très soigneusement les champs que vous souhaitez comparer, et si vous souhaitez comparer entre les champs. Vous pourriez même considérer les bigrams (paires de lettres; dans le cas de Duke Ellington, "Du", "Royaume-Uni", "Ke", "EE", et ainsi de suite.
Notez que, si vous avez beaucoup d'artiste particulier, cet artiste pourrait être déposé en priorité - vous pourriez entendre une piste par un artiste unique 5 fois, avant d'entendre les 10 pistes de Duke Ellington. Cela pourrait ou pourrait ne pas être ce que vous voulez. Vous pouvez éviter cela en mettant en place un dictionnaire de tout ce que vous avez à comparer, et combien de fois ils se produisent, donc si vous avez beaucoup de pistes de duc Ellington, deux pistes qui sont de Duke Ellington sont "moins similaires" que deux par Billy Joe Shaver .
Cela pourrait même valoir la peine de pré-associer une table avec chaque combinaison de deux paires de chansons. En outre, lorsque vous envisagez quelle chanson à jouer ensuite, vous n'avez besoin que de vous souvenir de la meilleure chanson jusqu'à présent; Si le prochain à considérer a un score pire que la meilleure chanson jusqu'à présent, vous pouvez passer à la suivante.