(* ideone.com/gtRf08 をF#で実装しました。 nenono.hatenablog.com/entry/2015/05/08/111710 を参考にしました。 よりランキングっぽい出力を得るため、以下の仕様としました。 * 1 origin (最初の値は0位ではなく1位) * 順位を決めるキーとなる値が等しいデータはすべて同一順位となる * 1位→2位→2位 の次の値の順位は4位となる *) // F# 4.0なら以下の関数の代わりにSeq.indexedが使える let indexed xs = xs |> Seq.mapi (fun i x -> i, x) // F# 4.0なら以下の関数の代わりにSeq.mapFoldが使える let mapFold mapping state xs = let result = ((None, state), xs) ||> Seq.scan (fun (_, s) x -> let m, s = mapping s x in Some m, s) (result |> Seq.map fst |> Seq.choose id), (result |> Seq.last |> snd) // 関数の本体 let ranked rankProjection xs = let rankMap = let sorted = xs |> Seq.map rankProjection |> indexed |> Seq.sortBy snd |> indexed ((1, None), sorted) ||> mapFold (fun (r, b) (ai, (bi, k)) -> let rank = if b = Some k then r else ai + 1 (bi, rank), (rank, Some k)) |> fst |> dict xs |> List.mapi (fun i x -> rankMap.[i], x) // テスト let test() = let inline shouldBe expected actual = if expected <> actual then failwithf "expected %A, but %A" expected actual let source = [ 3, 2 1, 7 4, 1 1, 8 5, 2 9, 8 2, 1 ] let expected = [ 4, (3, 2) 1, (1, 7) 5, (4, 1) 1, (1, 8) 6, (5, 2) 7, (9, 8) 3, (2, 1) ] source |> ranked fst |> shouldBe expected printfn "passed." test()