• Accumulating in hash-table

    From B. Pym@21:1/5 to All on Mon Jul 22 19:47:49 2024
    (defun distribution1 (items values test)
    (let ((table (make-hash-table :test test)))
    (loop for item in items
    for value in values
    do (incf (gethash item table 0) value))
    (let ((items-list nil))
    (maphash (lambda (item sum-value)
    (push (cons item sum-value) items-list))
    table)
    (sort items-list #'> :key #'cdr))))

    An example call:

    CL-USER 58 > (distribution1 '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9)
    #'equal)
    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8)
    ("g" . 7) ("u" . 7) ("r" . 5) ("e" . 3) ("z" . 3))

    Gauche Scheme

    (define (distribution1 items values test)
    (let1 table (make-hash-table test)
    (for-each
    (^(item value)
    (hash-table-update! table item (cut + value <>) 0))
    items
    values)
    (sort (hash-table->alist table) > cdr)))

    (distribution1 '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9)
    'equal?)

    ===>
    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8) ("g" . 7)
    ("u" . 7) ("r" . 5) ("z" . 3) ("e" . 3))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to B. Pym on Tue Jul 23 01:14:45 2024
    On 2024-07-22, B. Pym <Nobody447095@here-nor-there.org> wrote:
    (defun distribution1 (items values test)
    (let ((table (make-hash-table :test test)))
    (loop for item in items
    for value in values
    do (incf (gethash item table 0) value))
    (let ((items-list nil))
    (maphash (lambda (item sum-value)
    (push (cons item sum-value) items-list))
    table)
    (sort items-list #'> :key #'cdr))))

    An example call:

    CL-USER 58 > (distribution1 '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9)
    #'equal)
    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8)
    ("g" . 7) ("u" . 7) ("r" . 5) ("e" . 3) ("z" . 3))

    Gauche Scheme

    (define (distribution1 items values test)
    (let1 table (make-hash-table test)
    (for-each
    (^(item value)
    (hash-table-update! table item (cut + value <>) 0))
    items
    values)
    (sort (hash-table->alist table) > cdr)))

    (distribution1 '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9)
    'equal?)


    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8) ("g" . 7)
    ("u" . 7) ("r" . 5) ("z" . 3) ("e" . 3))


    This is the TXR Lisp interactive listener of TXR 294.
    Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
    I'm not addicted to procrastination. I can start any time I want to!
    (defun distrib (items values)
    (let ((h (hash)))
    (each ((i items) (v values))
    (inc [h i 0] v))
    [sort (hash-alist h) : car]))
    distrib
    (distrib '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9))
    (("a" . 15) ("b" . 12) ("c" . 8) ("e" . 3) ("f" . 17) ("g" . 7)
    ("h" . 9) ("k" . 25) ("r" . 5) ("u" . 7) ("z" . 3))

    Look how much the better code looks when you don't have silly
    things like a for-each that takes a lambda, and having to
    call a function with a functional argument to update a hash
    cell.

    Also, when you make equal hash tables default, most of the time
    it's the right default. You can skip the test arguments and whatnot.

    Names like "hash-table->alist" make my eyes bleed.

    Oops, I sorted on the wrong thing.

    (defun distrib (items values)
    (let ((h (hash)))
    (each ((i items) (v values))
    (inc [h i 0] v))
    [sort (hash-alist h) > cdr]))
    distrib
    (distrib '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9))
    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8)
    ("u" . 7) ("g" . 7) ("r" . 5) ("z" . 3) ("e" . 3))

    Using group-reduce:

    (defun distrib (items values)
    (flow [group-reduce (hash) car [mapf + use cdr]
    [mapcar cons items values] 0]
    hash-alist
    (sort @1 > cdr)))
    distrib
    (distrib '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9))
    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8)
    ("u" . 7) ("g" . 7) ("r" . 5) ("z" . 3) ("e" . 3))

    Using group-reduce on the keys, using pop to get the values,
    so we don't cons up list of pairs up-front:

    (defun distrib (items values)
    (flow [group-reduce (hash) identity [mapf + use (ret (pop values))]
    items 0]
    hash-alist
    (sort @1 > cdr)))
    distrib
    (distrib '("a" "b" "c" "b" "a" "f" "e" "g"
    "h" "k" "z" "k" "r" "u" "f")
    '(1 5 8 7 14 8 3 7 9 4 3 21 5 7 9))
    (("k" . 25) ("f" . 17) ("a" . 15) ("b" . 12) ("h" . 9) ("c" . 8)
    ("u" . 7) ("g" . 7) ("r" . 5) ("z" . 3) ("e" . 3))

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)