Haskell中数字列表的成对距离

时间:2015-03-02 16:51:21

标签: haskell combinatorics

如果X是一组数字,则ΔXmultiset个数字,表示每两个数字之间的成对减法。例如,如果X是一行中按升序排列的一组点,则ΔX是这些点之间成对距离的多重集。如何编写一个返回数字列表的成对距离的函数?以下工作,但我想要一个更优雅的解决方案。请包括理论或直觉,如果可能的话,可以提供如何解决类似问题的见解。

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]

3 个答案:

答案 0 :(得分:10)

distances xs = sort [ y - x | (x:ys) <- tails (sort xs), y <- ys ]

直觉:我们的想法是在xs中生成所有不同元素对。每个元素在列表中都有一些位置。如果我们在列表中x之前y,那么x是列表尾部的头部,而y位于尾部的某个位置。如果您先排序xs,然后排序y >= x。您可以在结尾处使用abs (y-x),而不是对xs进行排序。

答案 1 :(得分:3)

一种选择是将差异列表的生成与差异计算分开

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

这样你就可以写

pairwise_distances = sort . map (uncurry abs_distance) . pairs 

这当然更清洁(我认为,更优雅)虽然它可能不是你想要的那种优雅。

答案 2 :(得分:1)

它的拼写就像听起来一样。

 f xs = [x-x' | x <- xs, x' <- xs]

这当然会使每对计数两次,一次按顺序,一次按相反顺序计算,因此一半的距离将为负数。根据您的具体需要,您可以使用此项,或使用以下其中一项:

f xs = [abs(x-x') | x <- xs, x' <- xs]

f xs = [x-x' | x <- xs, x' <- xs, x>x']

后者依赖于xs是一个集合,即没有重复点,并且答案中不应包含任何零距离。