Rocksolid Light

News from da outaworlds

mail  files  register  groups  login

Message-ID:  

How apt the poor are to be proud. -- William Shakespeare, "Twelfth-Night"


comp / comp.lang.lisp / Re: Slow Loop (alternatives in lisp?)

SubjectAuthor
* Re: Slow Loop (alternatives in lisp?)B. Pym
`- Re: Slow Loop (alternatives in lisp?)Kaz Kylheku

1
Subject: Re: Slow Loop (alternatives in lisp?)
From: B. Pym
Newsgroups: comp.lang.lisp
Organization: A noiseless patient Spider
Date: Mon, 17 Jun 2024 23:45 UTC
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: No_spamming@noWhere_7073.org (B. Pym)
Newsgroups: comp.lang.lisp
Subject: Re: Slow Loop (alternatives in lisp?)
Date: Mon, 17 Jun 2024 23:45:07 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 71
Message-ID: <v4qhq1$vtkr$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Injection-Date: Tue, 18 Jun 2024 01:45:07 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="7f98368d3520ff7d5520391e04a235d5";
logging-data="1046171"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/tpSThTw+50J4rs6PxlzFJ"
User-Agent: XanaNews/1.18.1.6
Cancel-Lock: sha1:EEST6FLP3rih4IlSj1IQ5iAOGKY=
View all headers

Pascal Bourguignon wrote:

> > Hello, I'm trying to imitate the behaviour of the pivot-table in excel
> > where you take a list of items and another list of their values and
> > you sum similar ones together (see toy example below). I have a list
> > of 30000 items and their associated values and in excel using a pivot-
> > table the computation is done instantaneously (less than 2 seconds)
> > while the procedure I wrote in lisp will take about 12 hours !(I give
> > an example of only 15 items below, this goes fast of course because
> > only 15 items, but the 30,000 will take an estimate of about 12 hours;
> > I never reached that far because around 5 hours I give up). Do you
> > know why? Is there a way to enhance the procedure and make it as fast
> > as the pivot table? Thanks
>
>
> ;; Tabulate like the pivot table.
> (time
> (let ((ls (vector "a" "b" "c" "b" "a" "f" "e" "g"
> "h" "k" "z" "k" "r" "u" "f"))
> (counter (vector 1 5 8 7 14 8 3 7 9 4 3 21 5 7 9))
> (i 0))
> (loop while (< i (length ls)) do
> (let ((j (+ i 1)))
> (loop while (< j (length ls)) do
> (when (and (equal (elt ls i) (elt ls j))
> (not (equal (elt ls j) 'indic)))
> (incf (elt counter i) (elt counter j))
> (setf (elt ls j) 'indic
> (elt counter j) 'indic))
> (incf j)))
> (incf i))
> (values (delete 'indic ls)
> (delete 'indic counter))))
>
> Real time: 0.009765 sec.
> Run time: 0.012 sec.
> Space: 102408 Bytes
> #("a" "b" "c" "f" "e" "g" "h" "k" "z" "r" "u") ;
> #(15 12 8 17 3 7 9 25 3 5 7)

Gauche Scheme

(use srfi-13) ;; string<
(use srfi-43) ;; vector-binary-search

(define (string-cmp a b)
(cond ((string< a b) -1)
((string= a b) 0)
(else 1)))

(define (do-the-pivot keys counts)
(let* ((unique-keys
(sort (delete-duplicates (vector->list keys)) string<))
(pivot-keys (list->vector unique-keys))
(pivot-counts (make-vector (vector-length pivot-keys) 0)))
(vector-for-each
(lambda (_ k n)
(let ((i (vector-binary-search pivot-keys k string-cmp)))
(vector-set! pivot-counts i
(+ n (vector-ref pivot-counts i)))))
keys
counts)
(values pivot-keys pivot-counts)))

(do-the-pivot
#("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" "b" "c" "e" "f" "g" "h" "k" "r" "u" "z")
#(15 12 8 3 17 7 9 25 5 7 3)

Subject: Re: Slow Loop (alternatives in lisp?)
From: Kaz Kylheku
Newsgroups: comp.lang.lisp
Organization: A noiseless patient Spider
Date: Tue, 18 Jun 2024 02:07 UTC
References: 1
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: 643-408-1753@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.lisp
Subject: Re: Slow Loop (alternatives in lisp?)
Date: Tue, 18 Jun 2024 02:07:05 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 122
Message-ID: <20240617175526.907@kylheku.com>
References: <v4qhq1$vtkr$1@dont-email.me>
Injection-Date: Tue, 18 Jun 2024 04:07:06 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="acb487d277f52d684f55778f2fdee935";
logging-data="1216332"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+eN1Zc1Wf3EbqcYBR2J95+o8s/j64UK9Q="
User-Agent: slrn/pre1.0.4-9 (Linux)
Cancel-Lock: sha1:w2aFrx0BWpyTZKbYMcvX0R9O8lI=
View all headers

On 2024-06-17, B. Pym <No_spamming@noWhere_7073.org> wrote:
> Pascal Bourguignon wrote:
>
>> > Hello, I'm trying to imitate the behaviour of the pivot-table in excel
>> > where you take a list of items and another list of their values and
>> > you sum similar ones together (see toy example below). I have a list
>> > of 30000 items and their associated values and in excel using a pivot-
>> > table the computation is done instantaneously (less than 2 seconds)
>> > while the procedure I wrote in lisp will take about 12 hours !(I give
>> > an example of only 15 items below, this goes fast of course because
>> > only 15 items, but the 30,000 will take an estimate of about 12 hours;
>> > I never reached that far because around 5 hours I give up). Do you
>> > know why? Is there a way to enhance the procedure and make it as fast
>> > as the pivot table? Thanks
>>
>>
>> ;; Tabulate like the pivot table.
>> (time
>> (let ((ls (vector "a" "b" "c" "b" "a" "f" "e" "g"
>> "h" "k" "z" "k" "r" "u" "f"))
>> (counter (vector 1 5 8 7 14 8 3 7 9 4 3 21 5 7 9))
>> (i 0))
>> (loop while (< i (length ls)) do
>> (let ((j (+ i 1)))
>> (loop while (< j (length ls)) do
>> (when (and (equal (elt ls i) (elt ls j))
>> (not (equal (elt ls j) 'indic)))
>> (incf (elt counter i) (elt counter j))
>> (setf (elt ls j) 'indic
>> (elt counter j) 'indic))
>> (incf j)))
>> (incf i))
>> (values (delete 'indic ls)
>> (delete 'indic counter))))
>>
>> Real time: 0.009765 sec.
>> Run time: 0.012 sec.
>> Space: 102408 Bytes
>> #("a" "b" "c" "f" "e" "g" "h" "k" "z" "r" "u") ;
>> #(15 12 8 17 3 7 9 25 3 5 7)
>
> Gauche Scheme
>
> (use srfi-13) ;; string<
> (use srfi-43) ;; vector-binary-search
>
> (define (string-cmp a b)
> (cond ((string< a b) -1)
> ((string= a b) 0)
> (else 1)))
>
> (define (do-the-pivot keys counts)
> (let* ((unique-keys
> (sort (delete-duplicates (vector->list keys)) string<))
> (pivot-keys (list->vector unique-keys))
> (pivot-counts (make-vector (vector-length pivot-keys) 0)))
> (vector-for-each
> (lambda (_ k n)
> (let ((i (vector-binary-search pivot-keys k string-cmp)))
> (vector-set! pivot-counts i
> (+ n (vector-ref pivot-counts i)))))
> keys
> counts)
> (values pivot-keys pivot-counts)))
>
> (do-the-pivot
> #("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" "b" "c" "e" "f" "g" "h" "k" "r" "u" "z")
> #(15 12 8 3 17 7 9 25 5 7 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.
TXR is light and portable; take it camping, or to the Bahamas.
1> (defun pivot (k v)
(flow (list k v)
transpose
(sort-group @1 car)
(mapcar [juxt caar (op sum @1 cadr)])
transpose))
pivot
2> (pivot
#("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" "b" "c" "e" "f" "g" "h" "k" "r" "u" "z") (15 12 8 3 17 7 9 25 5 7 3))

Using group-reduce:

3> (defun pivot (k v)
(flow (list k v)
transpose
(group-reduce (hash) first [mapf + use second] @1 0)
hash-pairs
(sort @1 : first)
transpose))
pivot
4> (pivot
#("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" "b" "c" "e" "f" "g" "h" "k" "r" "u" "z") (15 12 8 3 17 7 9 25 5 7 3))

Nicer with group-map:

5> (defun pivot (k v)
(flow (list k v)
transpose
(group-map first (op sum @1 second))
hash-pairs
(sort @1 : first)
transpose))
pivot
6> (pivot
#("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" "b" "c" "e" "f" "g" "h" "k" "r" "u" "z") (15 12 8 3 17 7 9 25 5 7 3))

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

1

rocksolid light 0.9.8
clearnet tor