How to get every Nth element of an infinite list in Haskell?

后端 未结 23 1281
再見小時候
再見小時候 2020-12-04 23:58

More specifically, how do I generate a new list of every Nth element from an existing infinite list?

E.g. if the list is [5, 3, 0, 1, 8, 0, 3, 4, 0, 93, 211, 0

相关标签:
23条回答
  • 2020-12-05 00:46

    MHarris's answer is great. But I like to avoid using \, so here's my golf:

    extractEvery n
      = map snd . filter fst
      . zip (cycle (replicate (n-1) False ++ [True]))
    
    0 讨论(0)
  • 2020-12-05 00:48

    Another way of doing it:

    takeEveryM m lst = [n | (i,n) <- zip [1..] lst, i `mod` m == 0]
    

    Yet Another:

    import Data.List
    
    takeEveryMth m = 
      (unfoldr g)  . dr
         where 
           dr = drop (m-1)
           g (x:xs) = Just (x, dr xs)
           g []     = Nothing
    
    0 讨论(0)
  • 2020-12-05 00:52

    Explicit recursion is evil! Use a library construct like map, filter, fold, scan, reproduce, iterate etc instead. Unless it makes the code drastically easier to read even to those au fait with the libraries, then it's just making your code less modular, more verbose and harder to reason about.

    Seriously, the explicitly recursive versions need to be voted down to negative for a task as simple as this. Now I guess I should say something constructive to balance my carping.

    I prefer to use a map:

    every n xs = map (xs!!) [n-1,n-1+n..]

    rather than the ja's list comprehension so the reader doesn't have to worry about what i is. But either way it's O(n^2) when it could be O(n), so maybe this is better:

    every n = map (!!(n-1)) . iterate (drop n)

    0 讨论(0)
  • 2020-12-05 00:53

    A slightly silly version with foldr:

    everyNth n l = foldr cons nil l (n-1) where
      nil _ = []
      cons x rest 0 = x : rest n
      cons x rest n = rest (n-1)
    
    0 讨论(0)
  • 2020-12-05 00:54

    I don't have anything to test this with at work, but something like:

    extractEvery m = map snd . filter (\(x,y) -> (mod x m) == 0) . zip [1..]
    

    should work even on infinite lists.

    (Edit: tested and corrected.)

    0 讨论(0)
  • 2020-12-05 00:54

    Use a view pattern!

    {-# LANGUAGE ViewPatterns #-}
    
    everynth n (drop (n-1) -> l)
      | null l = []
      | otherwise = head l : everynth n (tail l)
    

    Ugly version of Nefrubyr's answer preserved so comments make sense.

    everynth :: Int -> [a] -> [a]
    everynth n l = case splitAt (n-1) l of
                     (_, (x:xs)) -> x : everynth n xs
                     _           -> []
    
    0 讨论(0)
提交回复
热议问题