「究極のシャッフル」アルゴリズムを作成して、mp3コレクションを並べ替えたい


33

私は、タイトルとアーティストの重複を避ける方法でmp3ファイルソートするための擬似コードの提案を探しています。私はクルーナーに耳を傾けます-フランク・シナトラ、トニー・ベネット、エラ・フィッツジェラルドなど、古い基準を歌います。各アーティストは、同じ曲を多数録音します-フライミートゥザムーン、ザウェイユールックトゥナイト、スターダストなど。2000曲あり、20曲がEllaのものである場合、100曲ごとに1回だけ聞きたいです。10人のアーティストがFly Me To The Moonを歌うなら、200曲に1回聴きたいです。もちろん、これら2つの要件を組み合わせて、「究極のシャッフル」を作成します。

これはかなり広範にわたる未解決の質問です。まだプログラミングを始めていませんので、良いアプローチの提案を探しています。実際には、他の曲の属性を均等に配置することに関して他のいくつかの要件がありますが、ここではそれに入りません。


出発点として、ここで見つけたコードを変更して、mp3ファイルを操作し、ID3タグを読み取ります。

以下のparsifalの回答を使用して、私のニーズを満たす小さなアプリを作成しました。ここにフォローアップの質問も書きました。素晴らしい反応をありがとう!


3
クールな質問、クールな問題、アルゴリズムを本当によく知っている人は、あなたのための正式な方法に基づいて素晴らしい答えを持っているでしょう。
ジミー・ホッファ

したがって、音楽コレクションの50%が同じアーティストのものである場合、他のアーティストが何人いるかに関係なく、2曲ごとにアーティストを聞きたいと思うでしょう。アイディア。たぶん私の意見ではありますが、それは「究極のシャッフル」のようには聞こえません。ただし、すべてのアーティストの曲の量がほぼ同じである場合を除きます。一方、アーティストの曲が1曲しかない場合は、あまり演奏したくありません。2つのバランスをとることは難しくありません。
ダケリング

私は次のような擬似コードをwhile (length(songs) > 0) { x := rand(); addElem(shuffle, songs[x]); remElem(songs, x); }実行します:、しかし、あなたは「究極のシャッフル」が欲しいと言います。私はあなたが本当にしても...質問を読ん、それにしたいのか分からない
コール・ジョンソン

曲リストをどこかにアップロードできますか-タイトルとアーティストタブまたはパイプ区切りまたはXML
tgkprog

Bansheeで(プラグインまたはコアとして)持っていると素敵です!
phw

回答:


5

プログラムを1回実行してプレイリストを生成しますか、それとも次の曲をライブで選択しますか?

後者の場合、答えは簡単です:

  • アーティストとタイトルを使用して、すべての曲を含む配列を作成します
  • 最近再生した曲のタイトルを保持するリスト(リンクリストが望ましい)を作成します。このリストは空で始まり、曲を再生するたびにリストに追加します。リストが目的の「曲の繰り返しなし」サイズに達したら、最も古い(最初の)エントリをドロップします。
  • アーティストのリストについても同じです。

曲を選ぶと、次の一連の手順になります。

  1. 「すべての曲」配列から曲をランダムに選択します。これは、0から配列のサイズまでの単なる乱数です。
  2. その曲が再生済みの曲リストに既にあるかどうかを確認します。ある場合は、手順1に戻ります。
  3. アーティストが再生済みアーティストリストに既にあるかどうかを確認します。ある場合は、手順1に戻ります。
  4. 曲のアーティスト/タイトルを適切なリストに追加し、必要に応じて古いエントリを削除します。
  5. 曲を再生します。

考えられる問題はいくつかありますが、実際のプロジェクトではなく、宿題としてこれを行う場合にのみ問題になります。

  • @Dukelingがコメントで述べたように、単一のアーティストまたは曲のタイトルを優先してコレクションが劇的にアンバランスな場合、曲を絶えず拒否するループに入る可能性があります。実際には、これは問題にはなりません。解決策は、「すでに見た」リストのサイズを小さくする必要があるということです。また、ステップ#2および#3でカウンターを追加すると、それが問題であるかどうかを確認できます(連続して10回失敗した場合は、警告を発生させるか、リストのサイズを小さくします)。
  • 1回だけ再生されたすべての曲を含むプレイリストを作成しようとしている場合は、ソース配列から曲を削除する必要があります。これにより、「最近再生された」障害が多すぎる場合の対処方法も変更されます(最終的に、ソース配列にアーティストが1人しかいない可能性があるため)。
  • ID3タグが私のタグのようなものである場合、それらには多くのスペルミスが含まれています。「デュークエリントン」は「デュークエリンテン」と異なる必要がありますか?「はい」の場合、「最近再生された」リストをスキャンするときに、Levensteinマッチャーの使用を検討します。

RockBox(rockbox.org)を使用します。曲の任意のフォルダーに対して、動的なプレイリストを作成できます(保存してブックマークすることもできます)。各曲のタイトル0001、0002の前に付けて、その順番で再生する予定です。
DeveloperDan

@DeveloperDan-同じプロセスが機能しますが、最後に注意するように、潜在的にルールに適合しない曲があります。次の2つの選択肢があります。ルールを調整して再実行するか、(あまりない場合は)曲をランダムに挿入します。
-parsifal

ステップ1でリストを作成し、2および3でリストから削除します。これにより、ループに陥るのが不可能になり、リストが空になった場合、ルールを変更して再スキャンする必要があります。より堅牢な方法。
マッケ14

13

ジェネレーター(C#では、yield各ループの反復を行う無限ループ)を使用する前に、このようなことをしました。各反復では、曲のプール(または何でも)を見て、最近再生された曲(または否定的な条件)を捨てます。次に、フィルタリングされたリストから1つを選択し、状態を更新します。状態が変化すると(シナトラ以外の曲を再生する)、条件が崩れ、除外された曲が再び含まれるようになります。

もちろん、対処すべきコーナーケースがあります。

  • すべての曲を捨てるとどうなりますか?(通常、状態を不安定にすることを望んで、ランダムに1つを選択します)
  • いくつかの基準を優先すべきですか?(通常、Fly Me to the Moonを連続して再生したくない場合があり、Sinatraを連続して再生したくない場合がありますが、それがすべての場合は...)
  • 曲のコレクションが戦闘中に更新されるとどうなりますか?(通常は簡単に対処できますが、使用状況によっては並行性に問題がある場合があります)

11

Telastynが提起するあなたの質問の外れ値を無視すると、ナップザック問題のバリエーションがあるように聞こえます。幸いなことに、それはかなりよく文書化されたアルゴリズムです。

ウィキペディアから

それぞれが重量と値を持つアイテムのセットを指定して、コレクションに含める各アイテムの数を決定し、合計重量が所定の制限以下で、合計値が可能な限り大きくなるようにします。

その記事には、ナップザック問題の追加リストとともに、関連する可能性のあるバリエーションがいくつかあります


ナップザック問題のバリエーションの1つは、多目的ナップザック問題です。アリコロニーアルゴリズムは、その問題を解決するための手段として提案されています。蟻コロニーのアプローチは、質問のNP困難な側面を避けるための最も簡単な方法かもしれません。

また、あなたの問題を巡回セールスマン問題の極端な変種と考えることもできます。訪問する各都市は本当にあなたが演奏したい曲ですが、アーティスト間の間隔をどのように指定するかはわかりません。この提案は、アリのコロニーによるアプローチにも関連している/解決できる。


8

私はこれが「ここに私のライブラリがあり、このプログラムを実行し、曲を再生するための命令を生成する」という仮定の下で働いています。

これは実装されておらず、シャッフルをどの程度うまく実行できるかはわかりません。フィルターが少し厳しすぎて、最初の曲のセットが与えられた場合、残りの部分が規定の順序になると思うかもしれません。

1つにはideal_gapハッシュがあります。これは、特定のプロパティ(アーティスト、アルバム、タイトル)を持つ曲の密度によって計算されます。2000曲あり、そのうち20曲がEllaというアーティストのものであるideal_gap{'artist'}{"ella"}場合、100 曲になります。

この情報を持つことは、最大のideal_gap値も持ちます。これを呼び出しましょうmax_gap

考えてみてくださいideal_gap。2人のアーティストだけが歌った曲が1000曲後に他の曲の再生を妨げないように最大値を設定し、max_gap値を大幅に増やして、「back off、no song、backオフ、曲なし」。

最後に再生されたmax_gapの曲を調べます(これは、フランクシナトラがFly Me To the Moonを歌うことで終わった場合、次の実行は偶然同じ曲で開始しないように、以前の実行から取り込むことができます)候補曲のセットをもたらすライブラリ。曲は、すべてのギャップがideal_gapそれらのプロパティのギャップよりも小さい場合にのみ候補曲に含まれます。

候補曲のセットから、ランダムに選択します。

考えてみましょう:より大きな最大ギャップを持つ属性を持つ曲がより可能性が高くなるように、セットに重みを付けます。このように、プレイリストの最後に最大ギャップの曲がすべて積み重なるわけではありません。

考えてみましょう:3つのプロパティすべてが理想的なギャップよりも大きいのではなく、3つのうち2つだけです。これは、理想的な理想よりも早く何かを再生できることを意味する場合がありますが、候補曲セットのサイズが大きくなり、「ランダムに1つを選択する」オプションが増えることを意味します。

要件を満たす曲がない場合はmax_gap、1ずつ減らし、すべてのideal_gapsをn/max_gapパーセントで減らしnます。これは、これが取り消された回数です。このようにmax_gap、100があり、この反復で5回バックオフされた場合、100のideal_gapは一時的に95に調整され、20のideal_gapは一時的に19に調整されます。少なくとも1つの候補曲ができるまでギャップし、上記のように選択します。

考慮してください:最小プールサイズを持っています。これは分散に追加されますが、再生可能な別の曲がある場合、理想的なギャップよりも早く曲が再生される可能性があります。


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曲ほど近い曲と照合するだけです。一般的な値の場合、この速度の最適化は結果の品質に実質的に影響しません。

特定のプロパティのまれな値の場合、それらの値を検索するよりも、その値の既存のインスタンスを追跡する方が効率的です。

インスタンスがほとんどない値は、間隔を空けるのではなく、均等に近づけることが重要であると考える場合、その基準の他の値ではなく、それらの特定の値の重みを大きくする必要があります。

リストからすべての可能なペアを等しい分布で選択する擬似ランダム関数は、通常のランダムピックよりもピックごとの効率がわずかに優れている場合があります。


あなたのアルゴリズムはシミュレーテッドアニーリングの一種であり、それをさらに洗練させるために見る場所になると思います。

@MichaelTいいえ、シミュレーテッドアニーリングは「温度」を使用します。これにより、局所的な最大値に陥ることを避けるために、より低い状態に回帰することができます。これは単なるローカル検索であり、シミュレーテッドアニーリング、または他の多くの確率的検索アルゴリズムのいずれかに比較的簡単に変更できますが、その必要性はあまりないと思います。基本的に、他のすべてのアルゴリズムが異なる方法で行うことは、局所的な最大値を回避しようとすることですが、許容できる解決策ではないこの問題の局所的な最大値を見つけるとは思いません。
aaaaaaaaaaaa

0

人々がとるさまざまなアプローチが興味深い。私は次のことをします:

これまでに再生されたすべてのトラックに基づいて、それぞれにスコアを付けます。最低スコアのトラックを再生します(または、同一のスコアの場合、最低スコアに一致するランダムなトラックを再生します)。繰り返す。

もちろん難しいのは、スコアを与えることです。次に再生する可能性のある各トラックについて、すでに再生した各トラック(または限られた数のトラック)を経由する必要があります。[次の可能性のある]トラックと[最近再生された]トラックに共通点がある場合、それらの共通点、共通点、[最近再生された]トラックがどれくらい前にあったかに応じて、スコアに追加します。遊んだ。「共通点がない」ことを0にしたいので、すべてのトラックを0から始めることができます。

あなたはおそらく数学を正しくするために、いくつかの手作りのプレイリストで実験したいと思うでしょう-あなたは共通の単語の数、共通の単語の数の平方、または数の平方根が欲しいですか共通の言葉の?プレイリスト全体に目を通し、「最も共通している」ものとしてトップに浮かぶものを確認し、バランスを正しくするために要因を微調整します。多分あなたは手紙ごとに行きたいので、「デューク・エリントン」は「デューク・エリントン」と比較して高いスコアを持っていますが、「キング・エル・デュトン」と比較するとさらに高いスコアを持っています(私は手紙を失っていない場合:) 。比較するフィールド、およびフィールド間で比較する場合は、慎重に検討する必要があります。バイグラム(文字のペア。デュークエリントンの場合、「Du」、

特定のアーティストが多数いる場合、そのアーティストが優先的にドロップダウンされる可能性があります-デュークエリントンの全トラックを聞く前に、ユニークなアーティストのトラックを5回聞くことがあります。これは、必要な場合とそうでない場合があります。これを回避するには、比較する必要のあるすべての辞書とそれらが発生する頻度を設定します。したがって、デュークエリントンのトラックが多数ある場合、デュークエリントンの2つのトラックはビリージョーシェーバーの2つのトラックよりも「似ていない」 。

2組の歌のすべての組み合わせでテーブルを事前に計算する価値さえあります。また、次に再生する曲を検討するときは、これまでで最高の曲を覚えるだけで済みます。次に考慮する曲のスコアがこれまでで最高の曲よりも悪い場合、次の曲にスキップできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.