ディレクトリ構造を維持した状態でシャッフル


音楽プレイヤーでランダムに曲を流す際に,全曲を完全にランダムにするのではなく,アルバムの順番をランダムにしてかつアルバム内の順番をシャッフル再生したい,と思うことがあるのではないでしょうか。

F# で上記のようなことを実現するために,構造を維持したままシャッフルするというのを実装してみました。

今メディアライブラリーが次のような構造をしているとします。

type MediaLibrary =
   | Media of string * string  // name * filepath
   | Directory of string * MediaLibrary list  // name * sublibrary

いわゆる普通のディレクトリ構造です。 Media が音楽メディア, Directory がディレクトリです。ディレクトリにはディレクトリもしくは音楽メディアが含まれます。

リストは次のようにシャッフルできます。

let shuffleList (random : Random) = List.sortBy (fun _ -> random.Next ())

これを用いてディレクトリ構造を維持したままのシャッフルは次のように実装できます。

let rec shuffleTree random = function
   | Media _ as media -> [media]
   | Directory (_, sub) -> List.collect (shuffleTree random) (shuffleList random sub)

これでディレクトリ構造を維持したまま音楽メディアをランダムな順番で取り出すことができます。

ちなみによくある完全シャッフルは次のように実装されます。

let rec flatten = function
   | Media _ as media -> [media]
   | Directory (_, sub) -> List.collect flatten sub

let shuffleAll random =
   flatten >> shuffleList random

更新履歴

  • [2012-09-22 01:25] concatMap を collect に修正。
  • [2012-09-22 01:55] shuffleList のアルゴリズムを差し替え。