2013-10-07 43 views
4

我有积极的评分列表的数组:地图排名在积极分数

[98.5, 85, 50, 50, 23, 0, 0, 0] 

我想行列分配给这些分数:

[1, 2, 3, 3, 4, 5, 5, 5] 

当两个连续的得分有相同的价值,他们得到相同的排名。 任何想法如何以功能的方式解决这个问题?

张贴在Haskell和红宝石,因为我认为这两种解决方案是可行的,可以移植

回答

11

在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] 
6

哈斯克尔:

{-# 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 < =>uniqelemIndex < =>index

+0

我也注意到,相关性。而“reverse”也是一样的。 – sawa

+0

@sawa我原本稍微怀疑OPs“将haskell移植到ruby中,反之亦然”,但似乎合理可行的哈哈。现在它变成了红宝石和哈斯克尔之间的人气比赛 – jozefg

+0

我对哈斯克尔了解不多,但是我听说它在数学上很漂亮。也许OP可能已经添加了lisp。 – sawa

1

不断所以,稍微比@sawa不同:

a = [98.5, 85, 50, 50, 23, 0, 0, 0] 
a.sort! {|e1,e2| -e1<=>-e2} # Just in case not already sorted 
h = Hash[a.uniq.each_with_index.to_a] 
a.map {|e| h[e]+1} 

# => [1, 2, 3, 3, 4, 5, 5, 5] 

编辑。我最初建议:

h = Hash[a.uniq.zip(1..a.size)] 
a.map {|e| h[e]} 
1

如果他们已经排序, 递归

eqNext (x:[email protected](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) 
1

我们是否假设分数已经排序?

这里是如何解决这个问题,如果他们不能假设排序:

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] 

首先,将反向索引每个分数。然后按元组的第二个投影按降序排列。按照第二个投影进行分组会给出我们必须具有相同排名的分数列表。用等级列表进行压缩将等级1赋予最大的等级。通过使用函数f,我们同时放弃实际分数,使元组成为一对(等级,反向索引)。现在需要按倒序索引的降序对这些元组进行排序,并得到第一个投影 - 排名。

1

另一个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]