Reputation: 47
I am trying to get all combinations of a list. The result for [1,2,3]
should be [(1,2),(1,3),(2,3)]
. My implementation below, however, gives [(1,2),(2,3)]
.
parings [d] = []
parings (y:ys) = (y, head ys): parings ys
Upvotes: 1
Views: 266
Reputation: 34378
Here is one implementation using tails
from Data.List
:
import Data.List
pairings :: [a] -> [(a, a)]
pairings = concatMap makePairs . tails
where
makePairs [] = []
makePairs (x:xs) = fmap ((,) x) xs
Notes:
I don't know whether tails
counts as a "special import" for you -- though it is not in the Prelude, it can be found in the base library, which is always available.
To see what tails
does, try tails [1..3]
.
((,) x)
is just a compact way of writing (\y -> (x, y))
. If you find it ugly, you can write the longer version instead, or enable the TupleSections
extension and spell it as (x,)
.
makePairs
might be written without explicit recursion as...
makePairs = maybe [] (\(x, xs) -> fmap ((,) x) xs) . uncons
... with uncons
also being found in Data.List
.
All the implementations in the answers here have a not insignificant problem: they retain consumed list segments in memory. To see what I'm talking about, watch the memory usage as you run head . drop 8000000 $ pairings [1..]
in GHCi. I'm not confident about there being a workaround for that -- a simple concat . tails
, for instance, appears to run into the same issue, while fmap makePairs . tails
doesn't (even head . drop (10^9) . head . drop (10^9) . fmap makePairs . tails $ [1..]
won't eat up all your memory).
Upvotes: 1
Reputation: 70267
The list comprehension mentioned in 9000's answer can be trivially factored into a map
call.
pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = map (\y -> (x, y)) xs ++ pairwise xs
Every list comprehension can be factored into some combination of map
, filter
, and concatMap
, possibly with some let
bindings interspersed. Doing so is a good exercise for learning how to manipulate functions.
Upvotes: 3
Reputation: 40884
I don't know why you're opposed to list comprehensions; with them, the solution is trivial:
pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = [(x, y) | y <- xs] ++ pairwise xs
You can factor out the comprehension into a separate function with explicit tail recursion if you want.
(The whole thing can be made tail-recursive, too, by keeping parameters for both sides of the ++
and having an accumulator parameter.)
Upvotes: 1