Hi all,
I want to take a list of lists, break it up into individual lists and
then mapcar a function over them.
For example, I want to split '((1 2 3) (4 5 6)) into '(1 2 3) and '(4
5 6) and then do (mapcar #'+ '(1 2 3) '(4 5 6) using the following
function:
((lambda (list) (mapcar #'+ (splitlist list)) '((1 2 3) (4 5 6)))
where splitlist is defined as :
(defun splitlist (list)
(apply #'values list))
At the top level (splitlist '((1 2 3) (4 5 6))) returns:
(1 2 3)
(4 5 6)
but (mapcar #'+ (splitlist '((1 2 3) (4 5 6))) returns (1 2 3) instead
of (5 7 9).
Is this not how the values function works?
Deech
deech wrote:
> Hi all,
> I want to take a list of lists, break it up into individual lists and
> then mapcar a function over them.
>
> For example, I want to split '((1 2 3) (4 5 6)) into '(1 2 3) and '(4
> 5 6) and then do (mapcar #'+ '(1 2 3) '(4 5 6) using the following
> function:
>
> ((lambda (list) (mapcar #'+ (splitlist list)) '((1 2 3) (4 5 6)))
>
> where splitlist is defined as :
> (defun splitlist (list)
> (apply #'values list))
>
> At the top level (splitlist '((1 2 3) (4 5 6))) returns:
> (1 2 3)
> (4 5 6)
>
> but (mapcar #'+ (splitlist '((1 2 3) (4 5 6))) returns (1 2 3) instead
> of (5 7 9).
>
> Is this not how the values function works?
Well you have proved that. :)
Try (mapcar '+ (splitlist ...))
Unless you do something in the caller that knows about multiple values
(such as multiple-value-bind or nth-value) you only see the first value.
kt
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
On Wed, 26 Mar 2008 13:24:19 -0700, deech wrote:
> Hi all,
> I want to take a list of lists, break it up into individual lists and
> then mapcar a function over them.
You've answered your own question there ... use MAP... you are not
'splitting a list' at all, but rather mapping or iterating over it.
> For example, I want to split '((1 2 3) (4 5 6)) into '(1 2 3) and '(4 5
> 6) and then do (mapcar #'+ '(1 2 3) '(4 5 6) using the following
> function:
>
> ((lambda (list) (mapcar #'+ (splitlist list)) '((1 2 3) (4 5 6)))
>
> where splitlist is defined as :
> (defun splitlist (list)
> (apply #'values list))
I have no idea what you expect this to do, or what you think VALUES does.
VALUES is used to return multiple values from a function. This is done
rarely, usually because a single return value does not convey enough
information (see gethash).
Unless you specifically request access to the extra values, they are
ignored. So while you think that:
>
> At the top level (splitlist '((1 2 3) (4 5 6))) returns: (1 2 3)
> (4 5 6)
...and FWIW that's actually what's happening, the thing returned by
SPLITLIST is actually multiple things that must be captured via one of
the MULTIPLE-VALUE-* operators.
>
> but (mapcar #'+ (splitlist '((1 2 3) (4 5 6))) returns (1 2 3) instead
> of (5 7 9).
Right, because it's only using the first return value and ignoring the
second.
> Is this not how the values function works?
Not at all. To make your 'splitlist' work you need to capture the
multiple values somehow... but again your whole idea does not make any
sense .. you want to split a list into it's elements, then what .. put
them back in a list so you can iterate over it?
You've somehow gotten yourself all turned around backwards. What you
should have done is reached for the CLHS (or whatever book you are
learning lisp from) and read about the mapping operators. After a lot of
playing around and learning, you might have been lucky enough to discover
MAP and REDUCE.
CL-USER> (map 'list #'+ '(1 2 3) '(4 5 6))
(5 7 9)
CL-USER> (reduce (lambda (x y) (map 'list '+ x y)) '((1 2 3) (4 5 6)))
(5 7 9)
;;;; Note that APPLY will also work for lists of length below CALL-
ARGUMENTS-LIMIT
CL-USER> (apply 'map 'list '+ '((1 2 3) (4 5 6)))
(5 7 9)
;;;; And that personally i don't like using LAMBDA when i don't have to:
CL-USER> (reduce (curry 'map 'list '+) '((1 2 3) (4 5 6)))
(5 7 9)
Hope that helps :).
Cheers,
drewc
Deech
--
Posted via a free Usenet account from http://www.teranews.com
P� Wed, 26 Mar 2008 21:24:19 +0100, skrev deech <············@gmail.com>:
> Hi all,
> I want to take a list of lists, break it up into individual lists and
> then mapcar a function over them.
>
> For example, I want to split '((1 2 3) (4 5 6)) into '(1 2 3) and '(4
> 5 6) and then do (mapcar #'+ '(1 2 3) '(4 5 6) using the following
> function:
>
> ((lambda (list) (mapcar #'+ (splitlist list)) '((1 2 3) (4 5 6)))
>
> where splitlist is defined as :
> (defun splitlist (list)
> (apply #'values list))
>
> At the top level (splitlist '((1 2 3) (4 5 6))) returns:
> (1 2 3)
> (4 5 6)
>
> but (mapcar #'+ (splitlist '((1 2 3) (4 5 6))) returns (1 2 3) instead
> of (5 7 9).
>
> Is this not how the values function works?
> Deech
Mapcar works on lists. It does not understand values returned on the stack.
What you want is to make a list with (mapcar #'+ '(1 2 3) '(4 5 6)).
So
(eval
(append
'(mapcar #'+)
(mapcar
(lambda (e) (if (consp e) (cons 'quote (list e)) e))
'((1 2 3) (4 5 6)))))
This is better expressed as a macro. (And loose the eval.) But it gives
you and idea how to start..
--------------
John Thingstad
P� Wed, 26 Mar 2008 21:56:55 +0100, skrev John Thingstad
<·······@online.no>:
>
> Mapcar works on lists. It does not understand values returned on the
> stack.
> What you want is to make a list with (mapcar #'+ '(1 2 3) '(4 5 6)).
> So
> (eval
> (append
> '(mapcar #'+)
> (mapcar
> (lambda (e) (if (consp e) (cons 'quote (list e)) e))
> '((1 2 3) (4 5 6)))))
>
> This is better expressed as a macro. (And loose the eval.) But it gives
> you and idea how to start..
>
This one is considerably less ugly..
(defmacro add(list) `(apply #'mapcar #'+ ,list))
(add '((1 2 3) (4 5 6)))
(5 7 9)
--------------
John Thingstad
This is really cool.
I never thought to use 'apply' like that before. Am I correct in
inferring that a statement like:
(apply #'mapcar #'+ '((1 2 3) (4 5 6)))
breaks down in the following way:
(apply #'(mapcar #+) '((1 2 3) (4 5 6)))
(apply #'(mapcar #+ '(1 2 3)) '((4 5 6)))
(mapcar #'+ '(1 2 3) '(4 5 6))
Deech
deech <············@gmail.com> writes:
> This is really cool.
>
> I never thought to use 'apply' like that before. Am I correct in
> inferring that a statement like:
> (apply #'mapcar #'+ '((1 2 3) (4 5 6)))
> breaks down in the following way:
Not exactly.
> (apply #'(mapcar #+) '((1 2 3) (4 5 6)))
The arguments all go together first (at least conceptually)
(apply #'mapcar '(#'+ (1 2 3) (4 5 6)))
> (mapcar #'+ '(1 2 3) '(4 5 6))
And then directly to this one.
--
Thomas A. Russ, USC/Information Sciences Institute
deech wrote:
> This is really cool.
>
> I never thought to use 'apply' like that before.
It worked?! :)
> Am I correct in
> inferring that a statement like:
> (apply #'mapcar #'+ '((1 2 3) (4 5 6)))
> breaks down in the following way:
> (apply #'(mapcar #+) '((1 2 3) (4 5 6)))
> (apply #'(mapcar #+ '(1 2 3)) '((4 5 6)))
> (mapcar #'+ '(1 2 3) '(4 5 6))
No, it goes straight to the last step. APPLY effectively appends the
last value to the others, and exists just for a case like yours where
the multiple list arguments you wanted to give to mapcar are bundled up
in one runtime value. If you knoe the splicing operator @:
(apply x y) -> (funcall x ,@y)
(apply x y z) -> (funcall x y ,@z)
Not that you can use @ like that, just giving you, um, my way of
thinking about it.
kenny
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
deech <············@gmail.com> writes:
> It seems to work fine.
>
> Here is my output from toplevel:
>
> CL-USER> (apply #'mapcar #'+ '((1 2 3) (4 5 6) (7 8 9)))
> (12 15 18)
But it doesn't:
C/USER1[325]> (apply (function mapcar) (function +)
(make-list (1+ call-arguments-limit) :initial-element '(1 2 3)))
*** - APPLY: too many arguments given to MAPCAR
--
__Pascal Bourguignon__ http://www.informatimago.com/
This universe shipped by weight, not volume. Some expansion may have
occurred during shipment.
Ken Tilton wrote:
>
>
> deech wrote:
>
>> This is really cool.
>>
>> I never thought to use 'apply' like that before.
>
>
> It worked?! :)
PWUAHAHAHAHAAAA -- I meant to say (APPLY #'mapcar ...) and then forgot
all about it, I see looking back.
Glad someone else got in there with it. This still holds...
> No, it goes straight to the last step. APPLY effectively appends the
> last value to the others, and exists just for a case like yours where
> the multiple list arguments you wanted to give to mapcar are bundled up
> in one runtime value. If you knoe the splicing operator @:
>
> (apply x y) -> (funcall x ,@y)
> (apply x y z) -> (funcall x y ,@z)
>
> Not that you can use @ like that, just giving you, um, my way of
> thinking about it.
>
> kenny
>
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
deech <············@gmail.com> writes:
> This is really cool.
>
> I never thought to use 'apply' like that before. Am I correct in
> inferring that a statement like:
> (apply #'mapcar #'+ '((1 2 3) (4 5 6)))
> breaks down in the following way:
> (apply #'(mapcar #+) '((1 2 3) (4 5 6)))
> (apply #'(mapcar #+ '(1 2 3)) '((4 5 6)))
> (mapcar #'+ '(1 2 3) '(4 5 6))
No, it's not correct. That's nonsensical. APPLY does not work like
this at all. Check CLHS.
--
__Pascal Bourguignon__ http://www.informatimago.com/
COMPONENT EQUIVALENCY NOTICE: The subatomic particles (electrons,
protons, etc.) comprising this product are exactly the same in every
measurable respect as those used in the products of other
manufacturers, and no claim to the contrary may legitimately be
expressed or implied.
P� Wed, 26 Mar 2008 22:11:53 +0100, skrev John Thingstad
<·······@online.no>:
>
> This one is considerably less ugly..
> (defmacro add(list) `(apply #'mapcar #'+ ,list))
> (add '((1 2 3) (4 5 6)))
> (5 7 9)
>
I should probably add that 'apply' has a limitation to the maximum number
of arguments. This is specified by a implementation dependent constant
lambda-parameter-limit which is spesified to be no less than 50 and
probably is 256 (LispWorks) or 1024 (most others). Thus the length of the
list passed in 'add' also has this limit. For a arbitrary length list use
reduce as Drew suggested.
--------------
John Thingstad
John Thingstad <·······@online.no> wrote:
+---------------
| This one is considerably less ugly..
| (defmacro add(list) `(apply #'mapcar #'+ ,list))
| (add '((1 2 3) (4 5 6)))
| (5 7 9)
+---------------
That reminds me of the ancient well-known hack for transposing a matrix
represented as a list of liists:
> (apply #'mapcar #'list '((1 2 3) (4 5 6) (7 8 9) (10 11 12)))
((1 4 7 10) (2 5 8 11) (3 6 9 12))
>
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
deech <············@gmail.com> writes:
> Hi all,
> I want to take a list of lists, break it up into individual lists and
> then mapcar a function over them.
>
> For example, I want to split '((1 2 3) (4 5 6)) into '(1 2 3) and '(4
> 5 6) and then do (mapcar #'+ '(1 2 3) '(4 5 6) using the following
> function:
>
> ((lambda (list) (mapcar #'+ (splitlist list)) '((1 2 3) (4 5 6)))
>
> where splitlist is defined as :
> (defun splitlist (list)
> (apply #'values list))
>
> At the top level (splitlist '((1 2 3) (4 5 6))) returns:
> (1 2 3)
> (4 5 6)
>
> but (mapcar #'+ (splitlist '((1 2 3) (4 5 6))) returns (1 2 3) instead
> of (5 7 9).
>
> Is this not how the values function works?
Yes it is.
To do what you want with multiple values, you have to use
MULTIPLE-VALUE-CALL:
(multiple-value-call (function mapcar) (function +)
(split-list '((1 2 3) (4 5 6))))
--> (5 7 9)
But multiple-values have restrictions that may be redhibitory: The
maximum number of values may be as low as 20 (See MULTIPLE-VALUES-LIMIT).
It would be better to use lists. Oops, you already have lists! How
nice, nothing to do!
(apply (function mapcar) (function +) '((1 2 3) (4 5 6)))
--> (5 7 9)
Well, better but not perfect. Indeed, now the limit is
CALL-ARGUMENTS-LIMIT which can be as low as 50.
The definitive way is to keep lists, but to use REDUCE instead of
APPLYxMAPCAR:
(reduce (lambda (a b) (mapcar (function +) a b)) '((1 2 3) (4 5 6)))
--> (5 7 9)
Of course this will cons-a-lot. To eliminate the consing we could
allocate a result and sum into it:
(let ((vectors '((1 2 3) (4 5 6))))
(let ((result (make-list (length (first vectors)) :initial-element 0)))
(dolist (vector vectors result)
(map-into result (function +) result vector))))
--> (5 7 9)
--
__Pascal Bourguignon__ http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
On Mar 26, 1:24 pm, deech <············@gmail.com> wrote:
> Hi all,
> I want to take a list of lists, break it up into individual lists and
> then mapcar a function over them.
>
> For example, I want to split '((1 2 3) (4 5 6)) into '(1 2 3) and '(4
> 5 6) and then do (mapcar #'+ '(1 2 3) '(4 5 6) using the following
> function:
In other words, the list '((1 2 3) (4 5 6) ...) holds the list of
trailing arguments to be passed to the MAPCAR function. What do we use
when we have a list of arguments? Answer: APPLY.
(apply #'mapcar #'+ '((1 2 3) (4 5 6)))
> ((lambda (list) (mapcar #'+ (splitlist list)) '((1 2 3) (4 5 6)))
Since SPLITLIST actually returns the pieces of the list as multiple
values, and we need those values to become individual arguments of
MAPCAR following the #'+, what we need is MULTIPLE-VALUE-CALL:
(multiple-value-call #'mapcar #'+ (splitlist list))
This is similar to how we used APPLY. Apply spreads lists into
individual function argumenst. MULTIPLE-VALUE-CALL spreads groups of
values into individual arguments.
> (defun splitlist (list)
> (apply #'values list))
But this is kind of pointless, because you might as well just keep the
list as a list, and spread it with APPLY, rather than convert it into
values which have to be spread with M-V-CALL.
> At the top level (splitlist '((1 2 3) (4 5 6))) returns:
> (1 2 3)
> (4 5 6)
>
> but (mapcar #'+ (splitlist '((1 2 3) (4 5 6))) returns (1 2 3) instead
> of (5 7 9).
Here, the (splitlist ...) expression is being evaluated in a context
where a single value is expected (it is an argument expression in a
function call). If it produces no values, then its value will be taken
to be NIL. If it produces two values or more, all but the first are
simply ignored.
So what is passed to MAPCAR is the single list (1 2 3). The + function
can be called with one argument, so you get (1 2 3).