Reputation:
Apologies for the awful title, I'm not too sure how to describe it in words but here is what I mean. If you know a better way to phrase this please let me know.
Suppose I had 2 lists, of equal length.
[a, b, c] [x, y, z]
I want to create the list
[[a, y, z], [b, x, z], [c, x, y]]
Essentially for every element of list1, I want the 2 elements at different indexes to the first element in list2.
so for "a" at index 0, the other 2 are "y" at index 1 and "z" at index 2.
I'm pretty sure I know how to do it using indexes, however, I know that that's not very efficient and wanted to see if there is a more functional solution out there.
Thank you.
Upvotes: 0
Views: 494
Reputation: 153342
I would do it using zippers. Here's a function I've written into so many projects I've memorized it:
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go b [] = []
go b (h:e) = (b, h, e) : go (h:b) e
(This actually returns a bit more information than we technically need for this application. But it is the general form -- useful in many situations where the restricted version that only returned the prefix/suffix pair and omitted the current focus would sometimes not be enough.)
With this tool in hand, we can just zip
(different kind of zip!) together the values from the one list with the zippers of the other list.
combine :: [a] -> [a] -> [[a]]
combine xs ys = zipWith (\x (b, h, e) -> reverse b ++ [x] ++ e) xs (zippers ys)
Try it out in ghci:
> combine "abc" "xyz"
["ayz","xbz","xyc"]
Upvotes: 2
Reputation: 3924
You haven't described any edge cases, but you can get the basic behavior you're looking for with something like:
import Data.List (inits, tails)
combine :: [a] -> [a] -> [[a]]
combine xs ys = zipWith3 go xs (tails ys) (inits ys)
where
go a (_:xs) ys = a:ys ++ xs
go _ _ _ = []
The key is that tails
returns successive suffixes of its list starting with the full list, and inits
returns successive prefixes starting with the empty list.
Upvotes: 2
Reputation: 875
You can try this:
\xs ys -> zipWith3 (((++) .) . (:)) xs (init $ inits ys) (tail $ tails ys)
Upvotes: 0