Algorithm Racket中的一个算法,它在列表之间对引用进行散列? 我们考虑一下这个列表: (define parts '(("a" "b" "c" "d" "e" "1") ("x" "y" "z" "a") ("q" "w" "e" "x") ("1" "2" "3" "4" "q")))

Algorithm Racket中的一个算法,它在列表之间对引用进行散列? 我们考虑一下这个列表: (define parts '(("a" "b" "c" "d" "e" "1") ("x" "y" "z" "a") ("q" "w" "e" "x") ("1" "2" "3" "4" "q"))),algorithm,hash,scheme,racket,Algorithm,Hash,Scheme,Racket,我需要做一个散列,其中每个第一个元素都是一个键,它的值是一个列表,在另一个列表中出现了对该键的引用。这是我期望的结果的一个例子: (define desired-result '#hash(("a" . ("x")) ("x" . ("q")) ("q" . ("1&q

我需要做一个散列,其中每个第一个元素都是一个键,它的值是一个列表,在另一个列表中出现了对该键的引用。这是我期望的结果的一个例子:

(define desired-result '#hash(("a" . ("x"))
                              ("x" . ("q"))
                              ("q" . ("1"))
                              ("1" . ("a"))))
如您所见,
“a”
(第一个列表中的第一个)由
“x”
(第二个列表中的
“a”
,以
“x”
开头)<代码>“x”由
“q”
等提到

我提出这段代码是为了更完整地了解“引用”的内容,但它并不是我所需要的,而且也很难看(可能很慢),请参见完整的代码:

#lang racket/base

(require racket/list)

(define parts '(("a" "b" "c" "d" "e" "1")
                ("x" "y" "z" "a")
                ("q" "w" "e" "x")
                ("1" "2" "3" "4" "q")))

(define my-hash (make-hash '()))

; This will initialize a key for every single element in parts
(for-each (λ (x)
            (hash-set! my-hash x '()))
          (remove-duplicates (flatten parts)))

(define (put x y)
  (hash-set! my-hash x y))

(define (get x)
  (hash-ref my-hash x))

(define (insert a n)
  (let ([aList (get a)]
        [nList (get n)])
    (unless (member n aList)
      (put a (append aList (list n))))
    (unless (member a nList)
      (put n (append nList (list a))))))

(define (iterate l)
  (let ([a (car l)]
        [r (cdr l)])
    (for-each (λ (n) (insert a n)) r)))

(for-each iterate parts)

my-hash
这将导致:

'#hash(("c" . ("a"))
       ("e" . ("a" "q"))
       ("2" . ("1"))
       ("a" . ("b" "c" "d" "e" "1" "x"))
       ("w" . ("q"))
       ("4" . ("1"))
       ("y" . ("x"))
       ("d" . ("a"))
       ("3" . ("1"))
       ("1" . ("a" "2" "3" "4" "q"))
       ("b" . ("a"))
       ("q" . ("w" "e" "x" "1"))
       ("x" . ("y" "z" "a" "q"))
       ("z" . ("x")))
当然有更好的方法来实现这一点(我很好奇是否有人能提出一些建议),我知道我可以从中得到
期望的结果,但这将更加丑陋

附言:

  • 这不是学校的作业
  • 我知道散列不是有序的
    • 这可能是您想要的:

      (define dwim
        (lambda (parts)
          (let loop ((todo parts)
                     (done '())
                     (result '()))
            (if (null? todo)
                result
                (let* ((key (caar todo))
                       (value
                        (fold
                         (lambda (lst previous)
                           (if (member key lst)
                               (cons (car lst) previous)
                               previous))
                         '()
                         (append (cdr todo) done))))
                  (loop (cdr todo)
                        (cons (car todo) done)
                        (cons (cons key value) result)))))))
      

      我的解决方案还使用哈希集来测试元素是否是前导元素的成员

      (define (process parts)
        (define leading-list (map first parts))
        (define leading-set (list->set leading-list))
        (define in-leading-set? (curry set-member? leading-set))
        (define my-hash (make-hash (map (curryr cons empty) leading-list)))
        (for-each
         (λ (lst)
           (for-each
            (λ (e)
              (hash-set! my-hash e (cons (first lst) (hash-ref my-hash e))))
            (filter in-leading-set? (rest lst))))
         parts)
        my-hash)
      
      这是输出

      > (process parts)
      '#hash(("1" . ("a")) ("x" . ("q")) ("q" . ("1")) ("a" . ("x")))
      
      这有一个警告,可能有一些元素映射到空列表。例如:

      > (define parts2 '(("a" "b")))
      > (process parts2)
      '#hash(("a" . ()))
      

      如果你不喜欢它们,你可以通过过滤掉它们来进行后期处理。

      可能是Racket针对列表(?)或集合的使用进行了优化(我在这里真的是在问),但从我的基准测试(100000次重复)来看,这比Michael Vehrs解决方案慢2到3倍。直觉上这应该更快。。。对于较大的
      部分
      列表,这可能有所不同,我必须尝试哈希表具有访问/修改恒定时间的理论性能,但分配表时会有开销,等等。我认为当输入非常大时,哈希表的性能将优于列表表(因为在列表上迭代需要线性时间,这对大的输入是不好的)。不管怎样,既然您要求一个哈希表解决方案,我就给您一个。我可以确认(基准测试)输入越大,你的算法就越快。请不要生气,我不是在批评,只是在分析,我很感谢你的帮助。我不觉得被冒犯了!这对你很有帮助:D谢谢你的回答,我不确定我是否完全明白,它比我聪明:D