Skip to main content

Chapter 6: Hash Tables, Maps, and Sets

  • Chapter
Common Lisp Recipes
  • 2046 Accesses

Abstract

As stated in the introduction to Chapter 5, lists aren’t the only data structure in Common Lisp. In addition to arrays, the standard also offers hash tables which are data structures that map keys to values by means of a hash function. Ideally, the cost of hash table lookups, as well as insertions or deletions of new entries, is independent of the number of elements stored in the table (although, see Recipe 6-5), which makes them a powerful alternative to other ways of organizing data.

This is a preview of subscription content, log in via an institution to check access.

Access this chapter

Chapter
USD 29.95
Price excludes VAT (USA)
  • Available as PDF
  • Read on any device
  • Instant download
  • Own it forever
eBook
USD 79.99
Price excludes VAT (USA)
  • Available as EPUB and PDF
  • Read on any device
  • Instant download
  • Own it forever
Softcover Book
USD 99.99
Price excludes VAT (USA)
  • Compact, lightweight edition
  • Dispatched in 3 to 5 business days
  • Free shipping worldwide - see info

Tax calculation will be finalised at checkout

Purchases are for personal use only

Institutional subscriptions

Notes

  1. 1.

    Although it can’t replace a decent textbook about data structures, of course.

  2. 2.

    And if you need to do that often, then a hash table is probably not the right data structure for your task.

  3. 3.

    You can, of course, associate a key with, say, a list of several objects. But technically it’d still be only one value—the list.

  4. 4.

    So, if you’re mathematically inclined, a hash table is just a way to represent a function, which is not necessarily injective. The set of keys is the domain of this function, while the set of values is its range.

  5. 5.

    The second return value shows that DONALD-DUCK is not a key of the hash table *H* (see Recipe 6-1).

  6. 6.

    For macros like INCF, see also page 291.

  7. 7.

    But see footnote 2.

  8. 8.

    Unless, of course, you use a non-local exit like THROW.

  9. 9.

    You could have written FOR YEAR = (GETHASH HERO *H*) instead, but that would most likely be pretty inefficient compared to what LOOP does. (Look at the macro expansion—it will almost certainly use WITH-HASH-TABLE-ITERATOR internally.)

  10. 10.

    You can’t even be sure to get the same order again if you immediately repeat an iteration although that’s probably a reasonable assumption for most implementations.

  11. 11.

    But see section 18.1.2.4!

  12. 12.

    That’s where the name hash table comes from, obviously.

  13. 13.

    This has the interesting consequence that you can’t utilize something like the memory address of an object to compute a hash as this address might change due to garbage collection.

  14. 14.

    In computer science parlance, this is a collision.

  15. 15.

    The library cl-custom-hash-table purports to provide a portability layer for this.

  16. 16.

    See page 142 for an explanation of this technique.

  17. 17.

    Much of what you’re seeing in this recipe is implementation-specific, but in its essence, it should still apply to other Lisp compilers as well. (Also, the output, which is from SBCL 1.2.9 on a 64-bit Linux system, has been edited a bit to reduce clutter.)

  18. 18.

    This parameter can also be an integer, in which case this number is added to the current size each time the hash table has to grow. That’d mean linear instead of exponential growth.

  19. 19.

    It turns out this is not what is actually happening. SBCL will multiply by 1.5, but then round to the next power of two; so if we start with 16, we’re effectively multiplying by 2 in each step. Still, there are quite a few hash tables that have to be created, only to be thrown away microseconds later.

  20. 20.

    As this will be a result of garbage collection, it is kind of unpredictable when it will actually happen. For the sake of this experiment, you might want to give your Lisp a helping hand by invoking the garbage collector explicitly (see Recipe 22-10).

  21. 21.

    In some Lisps you can even make a hash table weak after it has been created.

  22. 22.

    For an attempt to unify this, check out the trivial-garbage library (see also Recipe 22-10).

  23. 23.

    A fundamental difference between hash tables and alists in Common Lisp is how the identity of the data structure is provided. A hash table is represented as an object, and even if the data within the hash table changes, this object always stays the same. An alist, on the other hand, is represented by a cons cell. If you, for example, add an entry using ACONS, then you don’t modify the old alist, but instead you create a new one; that is, a new cons cell.

    In other words, if someone was holding a reference to the alist, then they wouldn’t “notice” that you prepended a new association. This wouldn’t happen to someone holding a reference to a hash table. (But see also page 162 for why this isn’t always an advantage.)

  24. 24.

    And please don’t ask why this is not called “PAIRLIST”…

  25. 25.

    Note the order of the result which tells us something about how this function is likely implemented in this particular implementation. This order is not mandated by the standard, though.

  26. 26.

    Or you could arrange an alist in such a way that entries that are looked up often come first.

  27. 27.

    Also called set-theoretic difference.

  28. 28.

    There’s no set-theoretical notation for this.

  29. 29.

    But you should, of course, be aware that PUSHNEW is a macro that modifies a place (see Recipe 10-8), whereas ADJOIN is a “pure” function.

  30. 30.

    When would they be too large? That, of course, depends on your application (see Recipe 17-2).

  31. 31.

    Note that we’re describing two different potential implementations here, although they would have very similar characteristics.

  32. 32.

    Both of these functions assume that keys are only present for set members and that all values are T.

  33. 33.

    For the binary representation used in this example, see Recipe 4-4.

Author information

Authors and Affiliations

Authors

Electronic Supplementary Material

Below is the link to the electronic supplementary material.

chapter-06 (zip 3 kb)

Rights and permissions

Reprints and permissions

Copyright information

© 2016 Edmund Weitz

About this chapter

Cite this chapter

Weitz, E. (2016). Chapter 6: Hash Tables, Maps, and Sets. In: Common Lisp Recipes. Apress, Berkeley, CA. https://doi.org/10.1007/978-1-4842-1176-2_6

Download citation

Publish with us

Policies and ethics