Racket 使用散列集的球拍中的平方欧氏距离

Racket 使用散列集的球拍中的平方欧氏距离,racket,Racket,我正在尝试编写一个函数来计算。我最初将数据存储在表单的列表中: '(1 8 0 0 0 1 0 5 0 1) '(1 0 2 0 0 0 0 5 0 0) 基本上我想得到的是: '(0 64 4 0 0 1 0 0 0 1) 使用列表并不难实现这一点,就像使用下面的代码一样: (define (f a b) (apply + (map (λ(x y) (sqr (- x y))) a b))) 然而,我正在处理的数据中有相当多的零,因此我尝试用哈希集替换列表,如下所示: '#hash(

我正在尝试编写一个函数来计算。我最初将数据存储在表单的列表中:

'(1 8 0 0 0 1 0 5 0 1)
'(1 0 2 0 0 0 0 5 0 0)
基本上我想得到的是:

'(0 64 4 0 0 1 0 0 0 1)
使用列表并不难实现这一点,就像使用下面的代码一样:

(define (f a b)
  (apply + (map (λ(x y) (sqr (- x y))) a b)))
然而,我正在处理的数据中有相当多的零,因此我尝试用哈希集替换列表,如下所示:

'#hash((0 . 1) (1 . 8) (5 . 1) (7 . 5) (9 . 1))
'#hash((0 . 1) (2 . 1) (7 . 5))
在这里,当我试图重写
f
函数,但使用散列集时,我陷入了困境,因为我不知道如何直接迭代这两个函数。到目前为止,我写的东西没有计算第二个哈希集中的元素,但没有计算第一个哈希集中的元素

(define (f a b)
  (for/fold ([sum 0])
            ([(k v) (in-hash a)])
    (+ sum (sqr (- (hash-ref b k 0) v)))))

是否有一种快速实现这一点的方法(最好使用单个for)?或者,有没有更好的方法来处理稀疏列表(包含许多零)?

问题是,我们需要处理两个哈希中缺少的值。仅对具有实际值的索引进行迭代,我们可以执行如下操作:

(define (squared-euclidean-distance a b)
  (for/fold ([sum 0])
            ([idx (set-union (hash-keys a) (hash-keys b))])
    (+ sum (sqr (- (hash-ref a idx 0)
                   (hash-ref b idx 0))))))
如果缺少索引,我们只需返回
0
。它按预期工作:

(squared-euclidean-distance
 '#hash((0 . 1) (1 . 8) (5 . 1) (7 . 5) (9 . 1))
 '#hash((0 . 1) (2 . 2) (7 . 5)))
=> 70

一种解决方案是获得任一稀疏向量中出现的所有索引的列表,然后映射到该索引列表以计算平方距离:

(定义(稀疏平方和u v)
(let((索引(删除重复项)(附加(散列键u)(散列键v '))))
(应用+(映射(λ(i)(let)((x(散列参考u i 0))
(y(散列参考v i 0)))
(sqr(-xy)))
(指数)
在开始使数据表示复杂化之前,您可能应该对数据进行一些实际测试,看看性能是否存在问题。在发布的示例中修复稀疏向量以使其匹配后,结果如下:

稀疏向量.rkt>(f'(1 80 0 0 1 0 5 0 1)
'(1 0 2 0 0 0 0 5 0 0))
70
稀疏向量.rkt>(稀疏平方和散列((0.1)(1.8)(5.1)(7.5)(9.1))
“#散列((0.1)(2.2)(7.5)))
70

注意,您的测试数据中有一个bug,在第二个散列中,您应该有一个
(2.2)
而不是
(2.1)