2015-03-02 28 views
2

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

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] 

回答

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是一套,它即没有重复的点,而且应包括在没有零距离答案。

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 

这肯定是清洁剂(和我会争辩,更优雅),虽然它可能不是你寻找的那种优雅。

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