Reputation: 379
Is there an easy-ish / general way to get consecutive n-tuples? For example:
f3 [1,2,3,4,5,6] = [(1,2,3),(2,3,4),(3,4,5),(4,5,6)]
f4 [1,2,3,4,5,6] = [(1,2,3,4),(2,3,4,5),(3,4,5,6)]
Similar question however it only covers pairs (x,y)
.
Upvotes: 1
Views: 129
Reputation: 50829
As @amalloy points out in the comments, there's no straightforward way to define this operation generally across different tuple sizes, but if you're just looking for a general pattern for writing a set of such functions, there are a few possibilities.
The simplest, though it looks a little physically repulsive, is just to write a simple recursive pattern match that spits out a tuple and then recurses on the tail of the argument, stopping as soon as the list becomes too short:
f3 :: [a] -> [(a,a,a)]
f3 (x1:nxt@(x2:x3:_)) = (x1,x2,x3):f3 nxt
f3 _ = []
f4 :: [a] -> [(a,a,a,a)]
f4 (x1:nxt@(x2:x3:x4:_)) = (x1,x2,x3,x4):f4 nxt
f4 _ = []
While you could generalize the solution you linked to for pairs by writing:
f3' = zip3 <*> tail <*> tail.tail
f4' = zip4 <*> tail <*> tail.tail <*> tail.tail.tail
this is too clever by half and also not a particularly efficient solution, as every argument repeats the tail operations of the previous argument when the results could be reused.
An alternative and probably reasonably approach is:
f3'' str = let l1:l2:l3:_ = tails str in zip3 l1 l2 l3
f4'' str = let l1:l2:l3:l4:_ = tails str in zip4 l1 l2 l3 l4
though it relies on having the right zipk
available. While zip3
is defined in Prelude
and zip4
through zip7
are defined in Data.List
, if you need zip8
or more, you need to define it yourself.
Upvotes: 2