私は肯定的なスコアのリストを持っています:
[98.5, 85, 50, 50, 23, 0, 0, 0]
これらのスコアにランクを割り当てたいと思います:
[1, 2, 3, 3, 4, 5, 5, 5]
連続する 2 つのスコアが同じ値の場合、それらは同じランクになります。これを機能的な方法で解決する方法はありますか?
( Haskell と Ruby で投稿されたのは、両方のソリューションが実行可能であり、移植できると思うためです)
ルビーの場合:
a = [98.5, 85, 50, 50, 23, 0, 0, 0]
sorted = a.sort.uniq.reverse
a.map{|e| sorted.index(e) + 1}
# => [1, 2, 3, 3, 4, 5, 5, 5]
ハスケル:
{-# LANGUAGE TupleSections #-}
import Data.List
import Data.Maybe (mapMaybe)
import Data.Function (on)
rank, rank' :: [Double] -> [Int]
rank ls = mapMaybe (fmap (+1) . (`elemIndex` sorted)) ls
where sorted = reverse . nub $ sort ls
-- Or Fixnum's faster solution
rank' = map fst . sortBy (compare `on` snd)
. concat . zipWith (\n -> map (n,)) [1..]
. groupBy ((==) `on` snd)
. sortBy (flip compare `on` snd) . zip [1::Int ..]
興味深いことに、rank
ほとんど澤さんの答えです。nub
<=>uniq
とelemIndex
<=> index
。
スコアがすでにソートされていると仮定しますか?
ソートされていると想定できない場合の解決方法は次のとおりです。
Prelude Data.List Data.Function> let f = (const .) . (,) :: a -> b -> c -> (a,b)
Prelude Data.List Data.Function> let sor s = sortBy ((flip compare) `on` snd) s
Prelude Data.List Data.Function> let rank scores = map fst . sor . concat .
zipWith (map . uncurry . f) [1..] . groupBy ((==) `on` snd) .
sor . zip [1,0..] $ scores
Prelude Data.List Data.Function> rank [11,13,13,12]
[3,1,1,2]
まず、各スコアに逆索引を付けます。次に、タプルの 2 番目の射影によって降順に並べ替えます。2 番目の射影でグループ化すると、同じランクでなければならないスコアのリストのリストが得られます。ランクのリストを圧縮すると、ランク 1 が最大数に割り当てられます。関数f
を使用することで、実際のスコアを同時に破棄し、タプルを (ランク、逆インデックス) のペアにします。次に、これらのタプルを逆インデックスの降順で並べ替え、最初の射影であるランクを取得する必要があります。
それらがすでにソートされている場合、 Recursive
eqNext (x:xs@(y:_)) acc =
let acc1 = if x == y then acc else acc + 1 in
acc1 : eqNext xs acc1
eqNext _ _ = []
els = 1 : eqNext ls 1
確認しよう:
> let ls = [98.5, 85, 50, 50, 23, 0, 0, 0]
> els
[1,2,3,3,4,5,5,5]
同じ非再帰的:
els = snd $ mapAccumL accF (0,0) ls
where
accF(ac,prev) b = let a1 = if ac == 0 || b /= prev then ac + 1 else ac in
((a1,b), a1)
別のRubyの答え:)
data = [98.5, 85, 50, 50, 23, 0, 0, 0, 85]
data.map{|value| data.select{|item| item > value }.size + 1 }
=> [1, 2, 4, 4, 6, 7, 7, 7, 2]