タイトルとアーティストの重複を避ける方法でmp3ファイルをソートするための疑似コードの提案を探しています。私はクルーナー-フランク・シナトラ、トニー・ベネット、エラ・フィッツジェラルドなどが古い基準を歌っているのを聞いています。それぞれのアーティストが同じ曲をたくさん録音します-Fly Me To The Moon、The Way You Look Tonight、Stardustなど。私の目標は、アーティストと曲のタイトルの間に最大のスペースで曲を配置(またはプレイリストを注文)することです。ですから、2000曲あり、20曲がEllaの場合、100曲に1度だけ彼女の話を聞きたいと思います。 10人のアーティストがFly Me To The Moonを歌うとしたら、200曲ごとに一度は聞きたいです。もちろん、これらの2つの要件を組み合わせて「究極のシャッフル」を作成したいと思います。
私はこれがかなり広く開かれた質問であることを知っています。まだプログラミングを開始していないので、適切なアプローチの提案を探しています。他の曲の属性を均等に配置することに関して他にもいくつかの要件がありますが、ここでは説明しません。
開始点として、私はコードを変更しています ここにあります でmp3ファイルを操作し、ID3タグを読み取ります。
以下のparsifalの答えを使用して、私のニーズを満たす小さなアプリを作成しました。フォローアップも書いた 質問はこちら 。すばらしい回答をありがとう!
プログラムを1回実行してプレイリストを生成しますか、それとも次の曲をライブで選びますか?
後者の場合、答えは簡単です:
曲を選ぶと、次の一連のステップになります。
いくつかの問題が考えられますが、実際のプロジェクトではなく、宿題としてこれを行っている場合にのみ問題が発生します。
ジェネレーターを使用する前に、私はこのようなことをしました(C#では、各ループ反復をyield
sする無限ループ)。各イテレーションでは、その曲のプール(または何でも)を調べ、最近再生されたもの(または何でも否定的な基準)を投げ捨てます。次に、フィルターされたリストから1つを選択し、状態を更新します。状態が変化すると(シナトラ以外の曲を再生します)、基準が崩れ、除外された曲が再び含まれ始めます。
もちろん、対処すべきコーナーケースがあります:
Telastynが提示する質問の外れ値を無視すると、 knapsack problem にバリエーションがあるように思えます。幸いなことに、これはかなりよく文書化されたアルゴリズムです。
ウィキペディアから
それぞれに重みと値が設定されたアイテムのセットを前提として、コレクションに含める各アイテムの数を決定します。これにより、合計の重みが特定の制限以下になり、合計値ができるだけ大きくなります。
追加の ナップザック問題のリスト とともに、その記事にはいくつかの潜在的に関連するバリエーションがリストされています。
ナップザック問題の1つのバリエーションは、多目的ナップザック問題です。 蟻コロニー アルゴリズムは、その問題を解決する手段として提案されています。アリコロニーアプローチは、質問のNPハードな側面を回避する最も簡単な方法かもしれません。
私はあなたの問題を traveling salesman 問題の極端な変形として考えることもできました。訪問する各都市は本当に演奏したい曲ですが、アーティスト間の間隔をどのように指定するかはわかりません。この提案は、アリのコロニーのアプローチにも関連していて、解決することができます。
私はこれが「ここに私のライブラリがあります。このプログラムを実行し、曲を再生するための注文を生成します」という前提で作業しています。
これは実装されておらず、シャッフルをどれだけうまく実行できるかは不明です。それは私がフィルターで少しtoo厳格であるかもしれません、それは結果として(私は信じて)最初の曲のセットを与えられた残りのための規定された順序になります。
1つはideal_gap
ハッシュを持っています。これは、特定のプロパティ(アーティスト、アルバム、タイトル)を持つ曲の密度によって計算されます。 2000曲あり、そのうちの20曲がエラというアーティストの場合、ideal_gap{'artist'}{"ella"}
は100になります。
この情報があると、ideal_gap値の最大値も得られます。これをmax_gap
と呼びましょう。
考慮してください:ideal_gap
の値を最大にして、2人のアーティストだけが歌った曲が1000曲後に他の曲を再生できないようにし、max_gap値を大幅に増やして「バックオフ」を何度も繰り返す、曲なし、バックオフ、曲なし」.
最後に再生されたmax_gapの曲を確認します(これは前の実行から入力できるため、Frank SinatraがFly Me To the Moonを歌って終了した場合、次の実行は偶然同じ曲で開始されません)。ライブラリは候補曲のセットをもたらします。すべてのギャップがそれらのプロパティのideal_gap
未満である場合にのみ、曲は候補曲に含まれます。
候補曲のセットから、ランダムに1つを選択します。
セットを重み付けして、最大ギャップが大きい属性の曲がより可能性が高くなるように重み付けします。この方法では、プレイリストの最後に最大ギャップの曲がすべて集まるわけではありません。
3つのプロパティすべてを理想的なギャップよりも大きくするのではなく、3つのうち2つだけにすることを検討してください。これは、理想的な理想よりも早く何かが再生される可能性があることを意味する可能性がありますが、候補曲セットのサイズが大きくなるため、「ランダムに1つを選択する」にはより多くのオプションがあります。
要件を満たす曲がない場合は、max_gap
を1だけバックオフし、ideal_gapsをすべてn/max_gap
パーセントだけオフにします。n
は、これがバックオフされた回数です。このように、100のmax_gap
があり、この反復で5回バックオフされた場合、100のideal_gapは一時的に95に調整され、20のideal_gapは一時的に19に調整されます。 。候補曲が1つ以上になるまでギャップを埋めて、上記のように選択します。
検討してください:最小のプールサイズを持っています。これにより差異が増えますが、再生できる別の曲がある場合、理想的なギャップよりも早く曲が再生される可能性があります。
これは最適化ジョブであり、the最適解を探している場合はかなり複雑なジョブです。幸い、私はそれが十分に良い結果をもたらすケースの1つであると信じています。
最初に行うことは、数学的品質基準を確立することです。これは、リストの順列が与えられると、その順列がどの程度良いか悪いかを説明する単一の数値を返す数式です。
単純な式の提案。考慮に入れたい各基準には重みを付け、重要な基準には高い重みを付け、多くの曲が同じプロパティを共有する基準には低い重みを付けて、それらが支配しないようにする必要があります:
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] )
このプロシージャが生成する値が低いほど、リストの順列はよくなります。
これで、この式をmath.stackexchangeに渡して、ほんのわずかな数の曲以外の最適なソリューションを見つけることは非常に難しく、おそらく実際には不可能であるか、またはクロックサイクルをスローして、良い解決策。
これを行うには多くの方法があります。1つは次のとおりです。
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
これはやや無駄なアルゴリズムですが、実装は簡単で、必要なだけの基準を処理できます。
さまざまな微調整や最適化の負荷を適用できます。以下にいくつか示します。
品質値の計算では、リスト内の他のすべての曲に対して曲をチェックするのではなく、代わりに100曲ほど近い曲と比較してください。一般的な値の場合、この速度の最適化は結果の品質に実質的に影響を与えません。
特定のプロパティのまれな値については、それらを検索するよりも、その値の既存のインスタンスを追跡する方が効率的な場合があります。
インスタンスの数が少ない値の間隔が離れているのではなく、均等に近いことが重要であると感じる場合は、それらの特定の値の重みを増やす必要がありますが、その基準の他の値の重みを増やす必要はありません。
リストからすべての可能なペアを等分布で選択する疑似ランダム関数は、通常のランダム選択よりも選択ごとにわずかに効率が良い場合があります。
人々が取るさまざまなアプローチが興味深いです。次のようにします。
これまでに再生されたすべてのトラックに基づいて、それぞれにスコアを付けます。最も低いスコアのトラックを再生します(または、同一のスコアの場合は、最も低いスコアに一致するランダムなトラックを再生します)。繰り返す。
もちろん、難しい点はスコアを与えることです。次に再生する可能性のあるトラックごとに、既に再生した各トラック(または限られた数)を通過する必要があります。 [次の可能性のある]トラックと[最近再生した]トラックに共通点がある場合は、共通点の数、共通点、および[最近再生した]トラックの経過時間に応じて、スコアに追加します演奏した。 「共通点は何もない」を0にする必要があるので、すべてのトラックを0から開始できます。
数学を正しくするために、最初にいくつかの手作りのプレイリストを試してみるとよいでしょう。共通の単語数、共通の単語数の2乗、または数の平方根のどちらが必要ですか。共通の言葉の?プレイリスト全体を実行し、どれが一番上に浮かぶのが「最も一般的」であるかを確認し、適切なバランスを得るために要素を手動で微調整します。たぶんあなたは手紙ごとに行きたいので、「デュークエリントン」は「デュークエリントン」と比較すると高いスコアを持っていますが、「キングエルデュトン」と比較するとさらに高いスコアを持っています(文字を失っていない場合:) 。比較するフィールド、およびフィールド間で比較する場合は、慎重に検討する必要があります。バイグラム(文字のペア。デュークエリントンの場合、 "Du"、 "uk"、 "ke"、 "ee"などを検討することもできます。
特定のアーティストがたくさんいる場合は、そのアーティストが優先的にドロップダウンされる可能性があることに注意してください。DukeEllingtonトラックの10個すべてを聞く前に、ユニークなアーティストのトラックを5回聞く場合があります。これはあなたが望むものかもしれませんし、そうでないかもしれません。比較する必要のあるものすべてとその発生頻度の辞書を設定することでこれを回避できます。そのため、Duke Ellingtonのトラックがたくさんある場合、Duke Ellingtonの2つのトラックはBilly Joe Shaverの2つのトラックより「似ていない」 。
2組の曲のすべての組み合わせでテーブルを事前に作成することもできます。また、次に再生する曲を検討するときは、これまでで最高の曲を覚えておけば十分です。次に検討する曲のスコアがこれまでの最高の曲よりも悪い場合は、次の曲にスキップできます。