From: deech
Subject: Mapcar'ing after splitting a list
Date: 
Message-ID: <bf641ce3-7ded-4a46-a8d2-04990101d612@e60g2000hsh.googlegroups.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

From: Ken Tilton
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <47eab60a$0$15158$607ed4bc@cv.net>
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
From: Drew Crampsie
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <47eaace0$0$26078$88260bb3@free.teranews.com>
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
From: William James
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <8a28cb1d-36ad-498c-9c69-71d0758ad3f2@h11g2000prf.googlegroups.com>
Drew Crampsie wrote:

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

Arc:

arc> (map + '(1 2 3) '(4 5 6))
(5 7 9)
arc> (apply map + '((1 2 3) (4 5 6)) )
(5 7 9)
arc> (reduce (fn (a b) (map + a b)) '((1 2 3)(4 5 6)(7 8 9)))
(12 15 18)

Using CL (COBOL-LISP) only makes things harder.
From: John Thingstad
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <op.t8m5s52out4oq5@pandora.alfanett.no>
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
From: John Thingstad
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <op.t8m6h3ifut4oq5@pandora.alfanett.no>
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
From: deech
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <482701e5-4bbf-48fc-9aed-2ab180fcfe5e@8g2000hse.googlegroups.com>
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
From: Thomas A. Russ
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <ymi1w5xruoy.fsf@blackcat.isi.edu>
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
From: Ken Tilton
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <47eac7f0$0$15201$607ed4bc@cv.net>
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
From: deech
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <d10fa291-3a52-4465-9112-27e9e82796f1@m34g2000hsc.googlegroups.com>
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)

Deech
From: Pascal Bourguignon
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <87skydqdg2.fsf@thalassa.informatimago.com>
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.
From: deech
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <6687879c-181f-4c28-b663-089cce77913b@b1g2000hsg.googlegroups.com>
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)

Deech
From: deech
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <2dfc173e-0d5a-4950-a09c-c564e5b7c9bc@a1g2000hsb.googlegroups.com>
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)

Deech
From: deech
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <eb478c9b-9a41-4cf5-9e8a-cf0fe01519a1@b64g2000hsa.googlegroups.com>
Sorry didn't mean to post a bunch of times.

Deech
From: deech
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <41c4cd00-5771-4b1e-956a-55bfdd3985d1@p73g2000hsd.googlegroups.com>
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)

Deech
From: Ken Tilton
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <47eacc2d$0$25023$607ed4bc@cv.net>
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
From: Pascal Bourguignon
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <87abklrw9x.fsf@thalassa.informatimago.com>
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.
From: John Thingstad
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <op.t8m7etcmut4oq5@pandora.alfanett.no>
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
From: Rob Warnock
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <YuCdnf3MWaHAw3banZ2dnUVZ_tHinZ2d@speakeasy.net>
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
From: Pascal Bourguignon
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <87ej9xrx5l.fsf@thalassa.informatimago.com>
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.
From: Kaz Kylheku
Subject: Re: Mapcar'ing after splitting a list
Date: 
Message-ID: <d94ee56a-0768-43ce-a7f0-9d819081840c@q78g2000hsh.googlegroups.com>
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).