Reputation: 18055
If X
is a set of numbers, then ΔX
is a multiset of numbers, representing pairwise subtractions between each 2 numbers. For example, if X
is a set of points on a line in increasing order, then ΔX
is a multiset of pairwise distances between these points. How to write a function that returns pairwise distances for a list of numbers? The below works, but I want a more elegant solution. Please include theory or intuitions, that might provide insight in how to solve similar problems, if possible.
pairwise_distances :: [Int] -> [Int]
pairwise_distances [] = []
pairwise_distances [x] = []
pairwise_distances (x:xs) = sort $ map (abs . (x-)) xs ++ pairwise_distances xs
pairwise_distances [3,2,1] -- [1,1,2]
pairwise_distances [0,2,4,7,10] -- [2,2,3,3,4,5,6,7,8,10]
Upvotes: 2
Views: 948
Reputation: 380
distances xs = sort [ y - x | (x:ys) <- tails (sort xs), y <- ys ]
Intuition: the idea is to generate all the pairs of distinct elements in xs
. Each element has some location in the list. If we take x
to come before y
on the list, then x
is the head of some tail of the list, and y
is somewhere in the tail of the tail. If you sort xs
first, then y >= x
. You could take abs (y-x)
at the end instead of sorting xs
.
Upvotes: 10
Reputation: 119877
It is spelled like it sounds.
f xs = [x-x' | x <- xs, x' <- xs]
This of course will have each pair counted twice, once in order and once in reverse order, so half of the distances will be negative. Depending on what exactly you need, you may use this, or one of the following:
f xs = [abs(x-x') | x <- xs, x' <- xs]
f xs = [x-x' | x <- xs, x' <- xs, x>x']
The latter relies on xs being a set, i.e. no duplicate points in it, and no zero distances that should be included in the answer.
Upvotes: 1
Reputation: 47392
One option is to separate the generation of lists of pairs from the calculation of differences
abs_distance x y = abs (x - y)
pairs [] = []
pairs (x:xs) = map (\y -> (x,y)) xs ++ pairs xs
-- or, with TupleSections enabled,
-- pairs (x:xs) = map (x,) xs ++ pairs xs
so that you can write
pairwise_distances = sort . map (uncurry abs_distance) . pairs
This is certainly cleaner (and, I would argue, more elegant) although it may not be the kind of elegance you are looking for.
Upvotes: 3