web-dev-qa-db-ja.com

MP3コレクションを並べ替える「究極のシャッフル」アルゴリズムを記述したい

タイトルとアーティストの重複を避ける方法で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の答えを使用して、私のニーズを満たす小さなアプリを作成しました。フォローアップも書いた 質問はこちら 。すばらしい回答をありがとう!

33
DeveloperDan

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

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

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

曲を選ぶと、次の一連のステップになります。

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

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

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

ジェネレーターを使用する前に、私はこのようなことをしました(C#では、各ループ反復をyieldsする無限ループ)。各イテレーションでは、その曲のプール(または何でも)を調べ、最近再生されたもの(または何でも否定的な基準)を投げ捨てます。次に、フィルターされたリストから1つを選択し、状態を更新します。状態が変化すると(シナトラ以外の曲を再生します)、基準が崩れ、除外された曲が再び含まれ始めます。

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

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

Telastynが提示する質問の外れ値を無視すると、 knapsack problem にバリエーションがあるように思えます。幸いなことに、これはかなりよく文書化されたアルゴリズムです。

ウィキペディアから

それぞれに重みと値が設定されたアイテムのセットを前提として、コレクションに含める各アイテムの数を決定します。これにより、合計の重みが特定の制限以下になり、合計値ができるだけ大きくなります。

追加の ナップザック問題のリスト とともに、その記事にはいくつかの潜在的に関連するバリエーションがリストされています。


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

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

11
user53019

私はこれが「ここに私のライブラリがあります。このプログラムを実行し、曲を再生するための注文を生成します」という前提で作業しています。

これは実装されておらず、シャッフルをどれだけうまく実行できるかは不明です。それは私がフィルターで少し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つ以上になるまでギャップを埋めて、上記のように選択します。

検討してください:最小のプールサイズを持っています。これにより差異が増えますが、再生できる別の曲がある場合、理想的なギャップよりも早く曲が再生される可能性があります。

8
user40980

これは最適化ジョブであり、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曲ほど近い曲と比較してください。一般的な値の場合、この速度の最適化は結果の品質に実質的に影響を与えません。

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

インスタンスの数が少ない値の間隔が離れているのではなく、均等に近いことが重要であると感じる場合は、それらの特定の値の重みを増やす必要がありますが、その基準の他の値の重みを増やす必要はありません。

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

1
aaaaaaaaaaaa

人々が取るさまざまなアプローチが興味深いです。次のようにします。

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

もちろん、難しい点はスコアを与えることです。次に再生する可能性のあるトラックごとに、既に再生した各トラック(または限られた数)を通過する必要があります。 [次の可能性のある]トラックと[最近再生した]トラックに共通点がある場合は、共通点の数、共通点、および[最近再生した]トラックの経過時間に応じて、スコアに追加します演奏した。 「共通点は何もない」を0にする必要があるので、すべてのトラックを0から開始できます。

数学を正しくするために、最初にいくつかの手作りのプレイリストを試してみるとよいでしょう。共通の単語数、共通の単語数の2乗、または数の平方根のどちらが必要ですか。共通の言葉の?プレイリスト全体を実行し、どれが一番上に浮かぶのが「最も一般的」であるかを確認し、適切なバランスを得るために要素を手動で微調整します。たぶんあなたは手紙ごとに行きたいので、「デュークエリントン」は「デュークエリントン」と比較すると高いスコアを持っていますが、「キングエルデュトン」と比較するとさらに高いスコアを持っています(文字を失っていない場合:) 。比較するフィールド、およびフィールド間で比較する場合は、慎重に検討する必要があります。バイグラム(文字のペア。デュークエリントンの場合、 "Du"、 "uk"、 "ke"、 "ee"などを検討することもできます。

特定のアーティストがたくさんいる場合は、そのアーティストが優先的にドロップダウンされる可能性があることに注意してください。DukeEllingtonトラックの10個すべてを聞く前に、ユニークなアーティストのトラックを5回聞く場合があります。これはあなたが望むものかもしれませんし、そうでないかもしれません。比較する必要のあるものすべてとその発生頻度の辞書を設定することでこれを回避できます。そのため、Duke Ellingtonのトラックがたくさんある場合、Duke Ellingtonの2つのトラックはBilly Joe Shaverの2つのトラックより「似ていない」 。

2組の曲のすべての組み合わせでテーブルを事前に作成することもできます。また、次に再生する曲を検討するときは、これまでで最高の曲を覚えておけば十分です。次に検討する曲のスコアがこれまでの最高の曲よりも悪い場合は、次の曲にスキップできます。

0
AMADANON Inc.