[Haskell-cafe] a sort of chunk
Viktor Dukhovni
ietf-dane at dukhovni.org
Sat Jan 18 00:08:37 UTC 2020
On Fri, Jan 17, 2020 at 05:41:12PM -0500, Viktor Dukhovni wrote:
> To your specific question I would refactor this a bit:
>
> -- | Split a list after the first element that reaches a target cumulative weight
> --
> splitWeight :: Int -> (a -> Int) -> [a] -> ([a], [a])
> splitWeight target weight xs =
> (,) <$> reverse . fst <*> snd $ go 0 xs []
> where
> go _ [] acc = (acc, [])
> go n (h:ts) acc
> | let w = n + weight h
> , w < target = go w ts $ h : acc
> | otherwise = (h : acc, ts)
An alternative implementation of splitWeight is lazier, and produces the
first element of the initial chunk in constant time even when the target
weight is large and requires billions of elements (on a 64bit system):
-- import Data.Bifunctor
splitWeight' :: Int -> (a -> Int) -> [a] -> ([a], [a])
splitWeight' target weight xs = go 0 xs
where
go _ [] = ([], [])
go n (h:ts)
| let w = n + weight h
, w < target = first (h:) $ go w ts
| otherwise = ([h], ts)
-- Define directly, or import from Data.Bifunctor
first f ~(a, b) = (f a, b)
λ> take 5 $ fst $ splitWeight' (maxBound :: Int) id [1..]
[1,2,3,4,5]
--
Viktor.
More information about the Haskell-Cafe
mailing list