There has -got- to be a nicer way to do this. It's space-efficient;
time-efficient too except the assoc ... but it looks like I'm writing
Python code in Lisp.
(defun pairs-to-bunch (pairs &key ((:test test) #'eql))
"((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 1 2) (B 2) (C 2 3))"
(loop with bunch = nil
for (one two) in pairs
for other-ones = (assoc one bunch :test test)
if (null other-ones)
do (push (cons one (list two)) bunch)
else
do (push two (cdr other-ones))
finally (return bunch)))
Here's the Python translation I did afterward:
def pairs_to_bunch(pairs):
bunch = {}
for (one, two) in pairs:
if one not in bunch:
bunch[one] = [two]
else:
bunch[one].append(two)
return bunch
It's fine Python, but I feel like it's weird Lisp. Am I being overly
critical?
--
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped. s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
Karl A. Krueger wrote:
> There has -got- to be a nicer way to do this. It's space-efficient;
> time-efficient too except the assoc ... but it looks like I'm writing
> Python code in Lisp.
>
>
> (defun pairs-to-bunch (pairs &key ((:test test) #'eql))
> "((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 1 2) (B 2) (C 2 3))"
> (loop with bunch = nil
> for (one two) in pairs
> for other-ones = (assoc one bunch :test test)
> if (null other-ones)
> do (push (cons one (list two)) bunch)
> else
> do (push two (cdr other-ones))
> finally (return bunch)))
>
>
> Here's the Python translation I did afterward:
>
> def pairs_to_bunch(pairs):
> bunch = {}
> for (one, two) in pairs:
> if one not in bunch:
> bunch[one] = [two]
> else:
> bunch[one].append(two)
> return bunch
>
>
> It's fine Python, but I feel like it's weird Lisp. Am I being overly
> critical?
(defun p2b (pairs &key ((:test test) #'eql))
"((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 1 2) (B 2) (C 2 3))"
(loop with bunch = nil
for (one two) in pairs
do (push two (cdr (or (assoc one bunch :test test)
(car (push (list one) bunch)))))
finally (return bunch)))
?
kenny
--
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
Espen Vestre wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
>
>
>>(defun p2b (pairs &key ((:test test) #'eql))
>> "((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 1 2) (B 2) (C 2 3))"
>> (loop with bunch = nil
>> for (one two) in pairs
>> do (push two (cdr (or (assoc one bunch :test test)
>> (car (push (list one) bunch)))))
>> finally (return bunch)))
>
>
> Nice version, but I'd ask the OP to consider using plists rather
> than alists. Things like this usually look neater with
> plists:
>
> (defun p2pb (pairs)
> (loop with bunch = nil
> for (one two) in pairs
> do (push two (getf bunch one))
> finally (return bunch)))
Wow. I came to Lisp late in life, went straight for the CLOS and never
paid much attention to punch-cardy plists. I knew about GET, but this is
behavior of GETF is news to me. Gotta go dig up all the code where I
re-invented it...
kenny
--
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
Kenny Tilton <·······@nyc.rr.com> writes:
> Wow. I came to Lisp late in life, went straight for the CLOS and never
> paid much attention to punch-cardy plists.
I'm a closmaniac myself, but you always need plists!
If not for anything else, then for make-instance argument list
construction :-)
--
(espen)
Espen Vestre wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
>
>
>>Wow. I came to Lisp late in life, went straight for the CLOS and never
>>paid much attention to punch-cardy plists.
>
>
> I'm a closmaniac myself, but you always need plists!
>
> If not for anything else, then for make-instance argument list
> construction :-)
Well I had come close to getf when I monkey-see-monkey-did a remf on
such an argument list, producing a long-standing undetected Cells bug
since it never occurred to the monkey on duty that remf was destructive,
despite the subtle tip-off in the name.
:)
kenny
--
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
Kenny Tilton wrote:
> Wow. I came to Lisp late in life, went straight for the CLOS and never
> paid much attention to punch-cardy plists. I knew about GET, but this is
> behavior of GETF is news to me. Gotta go dig up all the code where I
> re-invented it...
Recently I needed this, and found it very cool:
(incf (getf plist key 0))
This means: If the key is not bound in plist yet, assume 0 as its
default value.
So:
? (let ((plist '(:test1 4)))
(incf (getf plist :test1 0))
(incf (getf plist :test2 0))
plist)
(:TEST2 1 :TEST1 5)
Pascal
--
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
Pascal Costanza <········@web.de> wrote:
+---------------
| Recently I needed this, and found it very cool:
| (incf (getf plist key 0))
| This means: If the key is not bound in plist yet, assume 0 as its
| default value.
+---------------
And to bring this back around to hash tables (which the very
first responses in this thread suggested), for certain kinds
of text-processing tasks[1] I find myself doing this:
(incf (gethash key ht 0))
or this:
(push value (gethash key ht)) ; NIL is fine as a default here
-Rob
[1] Histograms, checking for uniqueness, etc.
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Espen Vestre <·····@*do-not-spam-me*.vestre.net> wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
>> (defun p2b (pairs &key ((:test test) #'eql))
>> "((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 1 2) (B 2) (C 2 3))"
>> (loop with bunch = nil
>> for (one two) in pairs
>> do (push two (cdr (or (assoc one bunch :test test)
>> (car (push (list one) bunch)))))
>> finally (return bunch)))
>
> Nice version, but I'd ask the OP to consider using plists rather
> than alists. Things like this usually look neater with
> plists:
>
> (defun p2pb (pairs)
> (loop with bunch = nil
> for (one two) in pairs
> do (push two (getf bunch one))
> finally (return bunch)))
Wow. Neat.
But GETF doesn't accept a :test argument like ASSOC does; it only uses
#'EQ ... so it does not work for strings, only symbols (or other things
that are EQ):
* (pairs-to-bunch '((llama rama) (llama pants)))
((LLAMA PANTS RAMA))
* (pairs-to-bunch '(("llama" "rama") ("llama" "pants")) :test #'string=)
(("llama" "pants" "rama"))
* (pairs-to-plist '((llama rama) (llama pants)))
(LLAMA (PANTS RAMA))
* (pairs-to-plist '(("llama" "rama") ("llama" "pants")))
("llama" ("pants") "llama" ("rama"))
And I'm working on strings, because that's what CLSQL hands me from my
database. So I'm sticking with alists for this one, but I'll keep
plists in mind for when I can use 'em -- the push/getf combination is
quite spiffy.
--
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped. s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
Karl A. Krueger wrote:
> But GETF doesn't accept a :test argument like ASSOC does; it only uses
> #'EQ ... so it does not work for strings
[...]
> And I'm working on strings, because that's what CLSQL hands me from my
> database.
You could create a package for things handed from the database, and
intern the strings you get in that package.
Pascal
--
ECOOP 2004 Workshops - Oslo, Norway
*1st European Lisp and Scheme Workshop, June 13*
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
*2nd Post-Java Workshop, June 14*
http://prog.vub.ac.be/~wdmeuter/PostJava04/
Pascal Costanza <········@web.de> wrote:
> Karl A. Krueger wrote:
>> But GETF doesn't accept a :test argument like ASSOC does; it only uses
>> #'EQ ... so it does not work for strings
> [...]
>> And I'm working on strings, because that's what CLSQL hands me from my
>> database.
>
> You could create a package for things handed from the database, and
> intern the strings you get in that package.
Could. #'STRING= is probably not that efficient, huh -- especially
since the strings in question are IP addresses with the same prefix.
Plenty to think about ... and this is just a simple report-generating
mod_lisp script. :)
--
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped. s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
* Kenny Tilton:
> (defun p2b (pairs &key ((:test test) #'eql))
> "((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 1 2) (B 2) (C 2 3))"
> (loop with bunch = nil
> for (one two) in pairs
> do (push two (cdr (or (assoc one bunch :test test)
> (car (push (list one) bunch)))))
> finally (return bunch)))
* Espen Vestre:
> Nice version, but I'd ask the OP to consider using plists rather
> than alists. Things like this usually look neater with
> plists:
>
> (defun p2pb (pairs)
> (loop with bunch = nil
> for (one two) in pairs
> do (push two (getf bunch one))
> finally (return bunch)))
Lispniks with get-assoc and (setf get-assoc) (modeled on getf) could
write
(defun pairs-to-bunch (pairs &key (test #'eql))
"((A 1) (A 2) (B 2) (C 2) (C 3)) ==> ((A 2 1) (B 2) (C 3 2))"
(loop with bunch = nil
for (one two) in pairs
do (push two (get-assoc one bunch :test test))
finally (return bunch)))
or something more elaborate, that respects the order of the pairs.
--
"Hurry if you still want to see something. Everything is vanishing."
-- Paul C�zanne (1839-1906)
On Wed, 21 Apr 2004, Karl A. Krueger <········@example.edu> wrote:
>
> def pairs_to_bunch(pairs):
> bunch = {}
> for (one, two) in pairs:
> if one not in bunch:
> bunch[one] = [two]
> else:
> bunch[one].append(two)
> return bunch
>
>
The direct translation looks very similar to me:
(defun pairs-to-bunch (pairs &key ((:test test) #'eql))
(loop with bunch = ()
for (first second) in pairs
for group = (assoc first bunch :test test)
do (if group
(push second (second group))
(push `(,first (,second)) bunch))
finally (return bunch)))
-- MMN