fork download
  1. (*
  2. ideone.com/gtRf08 をF#で実装しました。
  3. nenono.hatenablog.com/entry/2015/05/08/111710 を参考にしました。
  4.  
  5. よりランキングっぽい出力を得るため、以下の仕様としました。
  6. * 1 origin (最初の値は0位ではなく1)
  7. * 順位を決めるキーとなる値が等しいデータはすべて同一順位となる
  8. * 1位→2位→2位 の次の値の順位は4位となる
  9. *)
  10.  
  11. // F# 4.0なら以下の関数の代わりにSeq.indexedが使える
  12. let indexed xs = xs |> Seq.mapi (fun i x -> i, x)
  13.  
  14. // F# 4.0なら以下の関数の代わりにSeq.mapFoldが使える
  15. let mapFold mapping state xs =
  16. let result = ((None, state), xs) ||> Seq.scan (fun (_, s) x -> let m, s = mapping s x in Some m, s)
  17. (result |> Seq.map fst |> Seq.choose id), (result |> Seq.last |> snd)
  18.  
  19. // 関数の本体
  20. let ranked rankProjection xs =
  21. let rankMap =
  22. let sorted = xs |> Seq.map rankProjection |> indexed |> Seq.sortBy snd |> indexed
  23. ((1, None), sorted) ||> mapFold (fun (r, b) (ai, (bi, k)) ->
  24. let rank = if b = Some k then r else ai + 1
  25. (bi, rank), (rank, Some k))
  26. |> fst |> dict
  27. xs |> List.mapi (fun i x -> rankMap.[i], x)
  28.  
  29. // テスト
  30. let test() =
  31. let inline shouldBe expected actual =
  32. if expected <> actual then failwithf "expected %A, but %A" expected actual
  33.  
  34. let source = [
  35. 3, 2
  36. 1, 7
  37. 4, 1
  38. 1, 8
  39. 5, 2
  40. 9, 8
  41. 2, 1
  42. ]
  43. let expected = [
  44. 4, (3, 2)
  45. 1, (1, 7)
  46. 5, (4, 1)
  47. 1, (1, 8)
  48. 6, (5, 2)
  49. 7, (9, 8)
  50. 3, (2, 1)
  51. ]
  52. source |> ranked fst |> shouldBe expected
  53. printfn "passed."
  54.  
  55. test()
Success #stdin #stdout 0.18s 26056KB
stdin
Standard input is empty
stdout
passed.