Copy Hash Table in Lisp
Asked Answered
T

3

8

I have recently been working with hash tables in Common Lisp. I have been wondering how to make a separate copy of a hash table containing all the same values as the first. Is there an official way to do this? If not, can you give me an example using maphash?

Torsk answered 25/9, 2014 at 18:19 Comment(2)
I'm thinking you might also be interested in an immutable hash table. If you copy a lot it might be more effective.Insupportable
the widely used Alexandria library has a copy-hash-table functionParody
S
5

As clhs does not list a copy table function I'd assume that maphash is the way to go.

(defun copy-table (table)
  (let ((new-table (make-hash-table
                    :test (hash-table-test table)
                    :size (hash-table-size table))))
    (maphash #'(lambda(key value)
                 (setf (gethash key new-table) value))
             table)
    new-table))

(let ((table (make-hash-table)))
  (mapcar #'(lambda(arg argg)
              (setf (gethash arg table) argg))
          '(1 2 3 4) '(a b c d))
  (format t "~a~%" table)
  (format t "~a~%" (copy-table table)))

#<HASH-TABLE :TEST EQL :COUNT 4 {10063C7F13}>
#<HASH-TABLE :TEST EQL :COUNT 4 {10063C86D3}>

This function however does not take special configurations of the hashtable into account, but it should suffice as an example.

Shae answered 25/9, 2014 at 21:3 Comment(1)
Thanks, that did it, I was programming conway's game of life, I just needed to create a temporary copy i could modify for the next generation without affecting the current generation. Works great now.Torsk
M
7

Sim's answer copies a hash table, but there are two other features of hash tables thst might be good to copy for efficient population of the table. Here's a version that preserves that information, and also showcases loop's ability to work with hash tables (as an alternative to maphash):

(defun copy-hash-table (hash-table)
  (let ((ht (make-hash-table 
             :test (hash-table-test hash-table)
             :rehash-size (hash-table-rehash-size hash-table)
             :rehash-threshold (hash-table-rehash-threshold hash-table)
             :size (hash-table-size hash-table))))
    (loop for key being each hash-key of hash-table
       using (hash-value value)
       do (setf (gethash key ht) value)
       finally (return ht))))
                             
Maria answered 26/9, 2014 at 13:48 Comment(0)
D
6

Don't reinvent the wheel, use copy-hash-table from Alexandria.

Dessert answered 24/2, 2017 at 5:56 Comment(0)
S
5

As clhs does not list a copy table function I'd assume that maphash is the way to go.

(defun copy-table (table)
  (let ((new-table (make-hash-table
                    :test (hash-table-test table)
                    :size (hash-table-size table))))
    (maphash #'(lambda(key value)
                 (setf (gethash key new-table) value))
             table)
    new-table))

(let ((table (make-hash-table)))
  (mapcar #'(lambda(arg argg)
              (setf (gethash arg table) argg))
          '(1 2 3 4) '(a b c d))
  (format t "~a~%" table)
  (format t "~a~%" (copy-table table)))

#<HASH-TABLE :TEST EQL :COUNT 4 {10063C7F13}>
#<HASH-TABLE :TEST EQL :COUNT 4 {10063C86D3}>

This function however does not take special configurations of the hashtable into account, but it should suffice as an example.

Shae answered 25/9, 2014 at 21:3 Comment(1)
Thanks, that did it, I was programming conway's game of life, I just needed to create a temporary copy i could modify for the next generation without affecting the current generation. Works great now.Torsk

© 2022 - 2024 — McMap. All rights reserved.