How would be a functional approach to shifting certain array elements?

后端 未结 9 2057
感动是毒
感动是毒 2021-01-05 07:03

I have a Scala app with a list of items with checkboxes so the user select some, and click a button to shift them one position up (left). I decided to write a function to sh

9条回答
  •  孤街浪徒
    2021-01-05 07:18

    I don't know enough to write it in Scala, but this problem is tailor-made for the list functions takeWhile and dropWhile. The idea is that you split the list of items into three parts:

    • Left part, computed with takeWhile, contains leftmost elements not satisfying the predicate.

    • Middle part is the group of elements you want to shift left, computed by dropping the left elements and then takeWhile the remainder.

    • Right part is everything left over; dropWhile the middle elements.

    Here it is in Haskell:

    -- take first group of elements satisfying p and shift left one
    shift :: (a -> Bool) -> [a] -> [a]
    shift p l = case reverse left of 
                  []     -> l
                  (a:as) -> reverse as ++ middle ++ a : shift p right
      where left    = takeWhile (not . p) l  -- could be done with List.break
            notLeft = dropWhile (not . p) l
            middle  = takeWhile p notLeft    -- could be done with List.span
            right   = dropWhile p notLeft
    

    And here's a single unit test:

    *Shiftup> shift (>9) [1, 2, 3, 44, 55, 6, 7, 8]
    [1,2,44,55,3,6,7,8]
    

    Haskell programmers might use List.break or List.span to combine calls to takeWhile and dropWhile, but I'm not sure if Scala has these things. Besides, takeWhile and dropWhile are nice meaningful names, whereas I at least find break and span less perspicuous.

    EDIT: fixed recursive call to do shift p right instead of right to shift up all groups.

提交回复
热议问题