音楽プレイヤーでランダムに曲を流す際に,全曲を完全にランダムにするのではなく,アルバムの順番をランダムにしてかつアルバム内の順番をシャッフル再生したい,と思うことがあるのではないでしょうか。
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 のアルゴリズムを差し替え。