Deutsch   English   Français   Italiano  
<vatetl$lht1$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!2.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: "B. Pym" <Nobody447095@here-nor-there.org>
Newsgroups: comp.lang.lisp,comp.lang.scheme
Subject: Re: Basic List processing
Date: Fri, 30 Aug 2024 21:51:54 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 99
Message-ID: <vatetl$lht1$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Injection-Date: Fri, 30 Aug 2024 23:51:54 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="5f0439c3c250d854a4c9ef1a4e01f9df";
	logging-data="706465"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1+yLR9zh+Efv2ULNp81JR41"
User-Agent: XanaNews/1.18.1.6
Cancel-Lock: sha1:38RtFLLtQIAef5z208HNC7Csdb8=
Bytes: 3590

> > Suppose I have:
> >
> > (defvar *list*
> >    '((1 2)
> >      (3 4)
> >      (5 6)
> >      (1 7)))
> >
> >
> > Now, suppose I want the "keys" of the list, defined by the first element
> > of the list. Is there a Lisp function which is callable something like:
> > (keys *list* :key #'first) ; => '(1 3 5)
> >
> > Suppose further that I want to accumulate totals based on keys. The
> > first element in the list is the key, and the second element in the list
> > is the value. Is there a Lisp function which is callable something like:
> > (accum *list*) ; => '( (1 9) (3 4) (5 6) )
> 
> What we can do is define a somewhat general function for processing this type
> of associative list.
> 
>   (defun histogram (assoc-list reduce-func &rest reduce-args)
>     (let ((hash (make-hash-table :test #'eql)))
>       (loop for (key value) in assoc-list
>             do (push value (gethash key hash)))
>       (loop for key being the hash-keys of hash
>             using (hash-value value-list)
>             collect `(,key
>                       ,(apply #'reduce reduce-func value-list reduce-args)))))
> 
> What HISTOGRAM does is collates the values that share the same key into
> lists, and then it processes each list through REDUCE, so that you can
> summarize the values using arbitrary arithmetic, not only addition.
> 
> Some tests:
> 
> Add:
> 
>  (histogram '((1 2) (3 4) (5 6) (1 7)) #'+)
> 
>  -> ((5 6) (3 4) (1 9))
> 
> Multiply:
> 
>  (histogram '((1 2) (3 4) (5 6) (1 7)) #'*)
> 
>  -> ((5 6) (3 4) (1 14))
> 
> Add, supplying initial value for each summation:
> 
>  (histogram '((1 2) (3 4) (5 6) (1 7)) #'+ :initial-value 100)
> 
>  -> ((5 106) (3 104) (1 109))


Gauche Scheme:

(define data '((a 2) (b 5) (a 4) (b 3) (c 9)))

(rlet1 result '()
  (dolist (xs data)
    (ainc! result (car xs) (last xs))))

((c . 9) (b . 8) (a . 6))

(rlet1 result '()
  (dolist (xs data)
    (ainc! result (car xs) (last xs) * 1)))

((c . 9) (b . 15) (a . 8))

(rlet1 result '()
  (dolist (xs data)
    (ainc! result (car xs) (last xs) + 7000)))

((c . 7009) (b . 7008) (a . 7006))

(rlet1 result '()
  (dolist (xs data)
    (ainc! result (car xs) (last xs) cons '())))

((c 9) (b 3 5) (a 4 2))


Given:

(define-syntax ainc!
  (syntax-rules ()
    [(_ alist key val func default)
     (let ((pair (assoc key alist)))
       (if pair
         (set-cdr! pair (func val (cdr pair)))
         (set! alist (cons (cons key (func val default)) alist))))]
    [(_ alist key val func)
     (ainc! alist key val func 0)]
    [(_ alist key val)
     (ainc! alist key val +)]
    [(_ alist key)
     (ainc! alist key 1)]))