Code Golf: Shortest code to find a weighted median?

后端 未结 7 613
眼角桃花
眼角桃花 2021-01-03 08:23

My try at code golfing.

The problem of finding the minimum value of ∑W_i*|X-X_i| reduces to finding the weighted median of a list of x[i] with weights <

7条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-03 08:55

    Haskell code, ungolfed: trying for a reasonable functional solution.

    import Data.List (zip4)
    import Data.Maybe (listToMaybe)
    
    mid :: (Num a, Ord a) => [a] -> (Int, Bool)
    mid w = (i, total == part && maybe False (l ==) r) where
        (i, l, r, part):_ = dropWhile less . zip4 [0..] w v $ map (2*) sums
        _:sums = scanl (+) 0 w; total = last sums; less (_,_,_,x) = x < total
        v = map Just w ++ repeat Nothing
    
    wmedian :: (Num a, Ord a) => [a] -> [a] -> (a, Maybe a)
    wmedian w x = (left, if rem then listToMaybe rest else Nothing) where
        (i, rem) = mid w; left:rest = drop i x
    
    > wmedian [1,1,1,1] [1,2,3,4]
    (2,Just 3)
    > wmedian [1,1,2,1] [1,2,3,4]
    (3,Nothing)
    > wmedian [1,2,2,5] [1,2,3,4]
    (3,Just 4)
    > wmedian [1,2,2,6] [1,2,3,4]
    (4,Nothing)
    
    > wmedian [1..10] [0..9]
    (6,Nothing)
    > wmedian ([1..6]++[6..8]) [1..9]
    (6,Just 7)
    

    My original J solution was a straightforward translation of the above Haskell code.

    Here's a Haskell translation of the current J code:

    {-# LANGUAGE ParallelListComp #-}
    import Data.List (find); import Data.Maybe (fromJust)
    w&x=foldr((+).fst.fromJust.find((>=sum w).snd))0[f.g(+)0$map
        (2*)w|f<-[zip x.tail,reverse.zip x]|g<-[scanl,scanr]]/2
    

    Yeah… please don't write code like this.

    > [1,1,1,1]&[1,2,3,4]
    2.5
    > [1,1,2,1]&[1,2,3,4]
    3
    > [1,2,2,5]&[1,2,3,4]
    3.5
    > [1,2,2,6]&[1,2,3,4]
    4
    > [1..10]&[0..9]
    6
    > ([1..6]++[6..8])&[1..9]
    6.5
    

提交回复
热议问题