Rocksolid Light

News from da outaworlds

mail  files  register  groups  login

Message-ID:  

You are wise, witty, and wonderful, but you spend too much time reading this sort of trash.


comp / comp.lang.scheme / Re: Basic List processing

SubjectAuthor
o Re: Basic List processingB. Pym

1
Subject: Re: Basic List processing
From: B. Pym
Newsgroups: comp.lang.lisp, comp.lang.scheme
Organization: A noiseless patient Spider
Date: Fri, 30 Aug 2024 21:51 UTC
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Nobody447095@here-nor-there.org (B. Pym)
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=
View all headers

> > 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)]))

1

rocksolid light 0.9.8
clearnet tor