Aleksandar Sandic
2018-08-26 10:01:17 UTC
Hello everyone,
I have been looking through the reference manual, but there does not seem to
be a procedure for comparing two hash tables for equality. The procedure
'equal?' only returns true if the two tables are also 'eq?':
scheme@(guile-user)> (define h1 (make-hash-table))
scheme@(guile-user)> (define h2 (make-hash-table))
scheme@(guile-user)> (equal? h1 h2)
$1 = #f
scheme@(guile-user)> (equal? h1 h1)
$2 = #t
Is this the intended behaviour? If so, how can I compare two hash tables for
equality then? I have rolled my own function for the time being:
(define (hash-table-equal? h1 h2)
"- Scheme procedure: hash-table-equal? h1 h2
Compare two hash tables for entry-wise equality.
The arguments 'h1' and 'h2' are not equal if and only if either:
- One of them is not a hash table
- They do not have the same number of entries
- Values for the same key are not 'equal?' or 'hash-equal?'
Two hash tables are always 'hash-equal?' if they are 'eq?'."
;; First take care of the trivial cases. Then compare the length of the
;; tables; if the lengths don't match the tables not equal. Finally,
loop
;; over the keys of one table and compare the values with those in the
other
;; table.
;;
;; This algorithm traverses the first tables thrice and the second table
;; twice in the worst case: Once each to count the keys, once the first
one
;; to collect the keys, and once both to compare all values. The loop
will
;; terminate the instant a mismatch is found.
;;
;; If the first value is a hash table we call this function recursively
;; because hash tables are never 'equal?' (unless they are 'eq?')
(cond
((not (hash-table? h1)) #f)
((not (hash-table? h2)) #f)
((eq? h1 h2) #t)
(else
(let ((n-keys1 (hash-fold (λ (k v keys) (1+ keys)) 0 h1))
(n-keys2 (hash-fold (λ (k v keys) (1+ keys)) 0 h2)))
(if (not (= n-keys1 n-keys2))
#f
(do ((keys (hash-fold (λ (k v keys) (cons k keys)) '() h1) (cdr
keys))
(same? #t))
((or (not same?) (null? keys))
same?)
(let* ((key (car keys))
(v1 (hash-ref h1 key))
(v2 (hash-get-handle h2 key)))
(cond
((not v2) (set! same? #f))
((hash-table? v1) (set! same? (hash-table-equal?
v1 v2)))
((not (equal? v1 (cdr v2))) (set! same? #f))))))))))
I have been looking through the reference manual, but there does not seem to
be a procedure for comparing two hash tables for equality. The procedure
'equal?' only returns true if the two tables are also 'eq?':
scheme@(guile-user)> (define h1 (make-hash-table))
scheme@(guile-user)> (define h2 (make-hash-table))
scheme@(guile-user)> (equal? h1 h2)
$1 = #f
scheme@(guile-user)> (equal? h1 h1)
$2 = #t
Is this the intended behaviour? If so, how can I compare two hash tables for
equality then? I have rolled my own function for the time being:
(define (hash-table-equal? h1 h2)
"- Scheme procedure: hash-table-equal? h1 h2
Compare two hash tables for entry-wise equality.
The arguments 'h1' and 'h2' are not equal if and only if either:
- One of them is not a hash table
- They do not have the same number of entries
- Values for the same key are not 'equal?' or 'hash-equal?'
Two hash tables are always 'hash-equal?' if they are 'eq?'."
;; First take care of the trivial cases. Then compare the length of the
;; tables; if the lengths don't match the tables not equal. Finally,
loop
;; over the keys of one table and compare the values with those in the
other
;; table.
;;
;; This algorithm traverses the first tables thrice and the second table
;; twice in the worst case: Once each to count the keys, once the first
one
;; to collect the keys, and once both to compare all values. The loop
will
;; terminate the instant a mismatch is found.
;;
;; If the first value is a hash table we call this function recursively
;; because hash tables are never 'equal?' (unless they are 'eq?')
(cond
((not (hash-table? h1)) #f)
((not (hash-table? h2)) #f)
((eq? h1 h2) #t)
(else
(let ((n-keys1 (hash-fold (λ (k v keys) (1+ keys)) 0 h1))
(n-keys2 (hash-fold (λ (k v keys) (1+ keys)) 0 h2)))
(if (not (= n-keys1 n-keys2))
#f
(do ((keys (hash-fold (λ (k v keys) (cons k keys)) '() h1) (cdr
keys))
(same? #t))
((or (not same?) (null? keys))
same?)
(let* ((key (car keys))
(v1 (hash-ref h1 key))
(v2 (hash-get-handle h2 key)))
(cond
((not v2) (set! same? #f))
((hash-table? v1) (set! same? (hash-table-equal?
v1 v2)))
((not (equal? v1 (cdr v2))) (set! same? #f))))))))))