Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Another list of lists question

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
mracad
492 Views, 12 Replies

Another list of lists question

I have a list of lists. The 2nd item in each list is another list with an uncertain number of columns.

I am trying to add each column A,B,C for a total. (note - there can be more than 3 columns) 

Example list -

(setq ListX (list

    (list "1" (list "A" 0) (list "B" 1) (list "C" 0))

    (list "2" (list "A" 1) (list "B" 1) (list "C" 0))

    (list "3" (list "A" 0) (list "B" 1) (list "C" 2))

) )

 

I would like to end up with a list (1 3 2)

 

I just can't figure out how use mapcar, lambda and apply when the number of items in the list changes.

12 REPLIES 12
Message 2 of 13
Kent1Cooper
in reply to: mracad


@mracad wrote:

I have a list of lists. The 2nd item in each list is another list with an uncertain number of columns.

I am trying to add each column A,B,C for a total. (note - there can be more than 3 columns) 

Example list -

(setq ListX (list

    (list "1" (list "A" 0) (list "B" 1) (list "C" 0))

    (list "2" (list "A" 1) (list "B" 1) (list "C" 0))

    (list "3" (list "A" 0) (list "B" 1) (list "C" 2))

) )

 

I would like to end up with a list (1 3 2)

....


This sounds like a job for (foreach), in fact some nested (foreach) functions [not that there aren't other ways to do it, but this is what occurs to me].  Lightly tested on your example list only, it returns (1 2 3) rather than your (1 3 2), but I think that's what you're really expecting:

 

(foreach x ListX ; for each sub-list in the overall list

  (setq sum 0); start empty

  (foreach n (cdr x) ; for each item after the initial integer string

    (setq sum (+ (last n) sum)); add the final integer in the sub-sub-list to the total

  ); foreach [inner]

  (setq ListSums (append ListSums (list sum))); add to list of totals

); foreach [outer]

Kent Cooper, AIA
Message 3 of 13
Hallex
in reply to: mracad

Perhaps

 

(mapcar 'atoi (mapcar 'car ListX))

 

will do it

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 4 of 13
Kent1Cooper
in reply to: Hallex


@Hallex wrote:

Perhaps

 

(mapcar 'atoi (mapcar 'car ListX))

 

will do it


That gives the initial numerical text strings converted to integers, but what they're looking for is the sum of the last integers in the list of lists for each A/B/C in the sub-sub-lists.  It's just a coincidence that the result happens to be the same as my mistaken interpretation [see Message to follow] for this particular list of lists.

Kent Cooper, AIA
Message 5 of 13
Kent1Cooper
in reply to: Kent1Cooper

No, I misinterpreted what's wanted.  I added up the A B & C in each line, whereas I see now that you want the A's added together, and the B's and C's and however far it goes likewise.  I'll try a revision later, but I wanted you to know that I realized my suggestion doesn't actually do what you're looking for.

 

Would all sub-lists always be the same length as each other?  And would the letter parts always be in the same order, or might any sometimes have them out of alphabetical order, or possibly not have all letters in a contiguous series [e.g. A B D G]?  That could have a large effect on how one would go about it.

Kent Cooper, AIA
Message 6 of 13
Hallex
in reply to: Kent1Cooper

Sorry for my misunderstanding,

then probably we use recursive way

(defun sum-inner(lst)
  (if lst
    (cons (apply '+ (mapcar 'cadr (cdar lst)))(sum-inner (cdr lst)))))
; Usage:
;(setq result (sum-inner ListX));<-- (1 2 3)

 Regards,

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 7 of 13
phanaem
in reply to: mracad

(apply 'mapcar (cons '+ (mapcar (function (lambda (x) (mapcar 'last x))) (mapcar 'cdr ListX))))

 

Message 8 of 13
Kent1Cooper
in reply to: phanaem

The phanaem and Hallex suggestions look clever and concise, but they do depend on the "right" answer to one of my questions:  do all sub-sub-lists have the same series of letters beginning the same items?  If, for example, a list were like this:

 

(setq ListX

  (list

    (list "1" (list "A" 0) (list "B" 1) (list "C" 0))

    (list "2" (list "A" 1) (list "B" 1) (list "D" 0))

    (list "3" (list "B" 0) (list "C" 1) (list "D" 2))

  )

)

 

those routines would be adding A's to B's, and B's to C's, and C's to D's.  If that's a possibility, some approach that looks at the letter item of each sub-sub-list would be needed.  But I'll wait to hear from the OP before pursuing that any further.

Kent Cooper, AIA
Message 9 of 13
mracad
in reply to: Kent1Cooper

SORRY guys..I made a mistake with the list. There should have been -

(setq ListX (list
                    (list "1" (list (list "A" 0) (list "B" 1) (list "C" 0)))
                    (list "2" (list (list "A" 1) (list "B" 1) (list "C" 0)))
                    (list "3" (list (list "A" 0) (list "B" 1) (list "C" 2)))
                  )
 )

 

This way the second item in the list is a list of lists. Note, there will be additions items in each list after the 2nd item.

This 2nd item list can have 5+ lists of 2 values (ex. "A" 0) and the "A", "B", etc are simplification of actual text as the 1st value.

I am just wanting to take the 2nd item in each list, then cumulative add up the 2nd item in each item.

 

Another example -

       (setq ListX (list
                    (list "1" (list (list "A" 9) (list "B"  0) (list "C" 5) (list "D" 17)))
                    (list "2" (list (list "A" 1) (list "B" 12) (list "C" 9) (list "D"  6)))
                    (list "3" (list (list "A" 0) (list "B" 21) (list "C" 4) (list "D" 11)))
                  )
      )

would return (10 33 18 34 )

 

Here is an actual list -

(setq ListX
  (list (list 5x5    (list (list "DOQ"  0) (list "CCDOQ" 0) (list "DIQ" 3) (list "CCDIQ" 34) (list "UIQ" 0) (list "CCUIQ" 2)) 39 16  975)
        (list 5x10   (list (list "DOQ"  0) (list "CCDOQ" 2) (list "DIQ" 0) (list "CCDIQ" 31) (list "UIQ" 7) (list "CCUIQ" 1)) 41 17 2050)
        (list 7.5x10 (list (list "DOQ"  0) (list "CCDOQ" 0) (list "DIQ" 0) (list "CCDIQ" 20) (list "UIQ" 0) (list "CCUIQ" 0)) 20  8 1500)
        (list 10x10  (list (list "DOQ"  5) (list "CCDOQ" 5) (list "DIQ" 0) (list "CCDIQ" 26) (list "UIQ" 0) (list "CCUIQ" 1)) 37 15 3700)
        (list 10x15  (list (list "DOQ" 16) (list "CCDOQ" 0) (list "DIQ" 0) (list "CCDIQ" 16) (list "UIQ" 0) (list "CCUIQ" 1)) 33 13 4950)
        (list 10x20  (list (list "DOQ" 24) (list "CCDOQ" 0) (list "DIQ" 3) (list "CCDIQ"  0) (list "UIQ" 😎 (list "CCUIQ" 0)) 35 14 7000)
        (list 10x25  (list (list "DOQ"  2) (list "CCDOQ" 😎 (list "DIQ" 0) (list "CCDIQ"  0) (list "UIQ" 0) (list "CCUIQ" 9)) 19  8 4750)
        (list 10x30  (list (list "DOQ" 13) (list "CCDOQ" 0) (list "DIQ" 0) (list "CCDIQ"  0) (list "UIQ" 9) (list "CCUIQ" 1)) 23  9 6900)
))

would return

(60 15 6 127 24 15)

Message 10 of 13
dbroad
in reply to: mracad

This would work.  You probably should leave the last line commented out until you are sure that it gives you what you want.  Because this uses assoc, it does not depend on the order of the keyed sublists.

 

(defun addstuff (lst / rtn el);;DCBroad - Special list add
  (foreach n (mapcar 'cadr lst)
    (foreach m (reverse n)
      (if (setq el (assoc (car m) rtn))
	(setq rtn (subst (list (car m) (+ (cadr el)(cadr m))) el rtn))
	(setq rtn (cons m rtn))
	)
      )
    )
  ;(mapcar 'cadr rtn);;uncomment this out for unkeyed list
  )

 

;;Tested on this list
(setq ListX 
  (list (list "5x5"    (list (list "DOQ"  0) (list "CCDOQ" 0) (list "DIQ" 3) (list "CCDIQ" 34) (list "UIQ" 0) (list "CCUIQ" 2)) 39 16  975)
        (list "5x10"   (list (list "DOQ"  0) (list "CCDOQ" 2) (list "DIQ" 0) (list "CCDIQ" 31) (list "UIQ" 7) (list "CCUIQ" 1)) 41 17 2050)
        (list "7.5x10" (list (list "DOQ"  0) (list "CCDOQ" 0) (list "DIQ" 0) (list "CCDIQ" 20) (list "UIQ" 0) (list "CCUIQ" 0)) 20  8 1500)
        (list "10x10"  (list (list "DOQ"  5) (list "CCDOQ" 5) (list "DIQ" 0) (list "CCDIQ" 26) (list "UIQ" 0) (list "CCUIQ" 1)) 37 15 3700)
        (list "10x15"  (list (list "DOQ" 16) (list "CCDOQ" 0) (list "DIQ" 0) (list "CCDIQ" 16) (list "UIQ" 0) (list "CCUIQ" 1)) 33 13 4950)
        (list "10x20"  (list (list "DOQ" 24) (list "CCDOQ" 0) (list "DIQ" 3) (list "CCDIQ"  0) (list "UIQ" 8) (list "CCUIQ" 0)) 35 14 7000)
        (list "10x25"  (list (list "DOQ"  2) (list "CCDOQ" 8) (list "DIQ" 0) (list "CCDIQ"  0) (list "UIQ" 0) (list "CCUIQ" 9)) 19  8 4750)
        (list "10x30"  (list (list "DOQ" 13) (list "CCDOQ" 0) (list "DIQ" 0) (list "CCDIQ"  0) (list "UIQ" 9) (list "CCUIQ" 1)) 23  9 6900)
))

 returns

(("DOQ" 60) ("CCDOQ" 15) ("DIQ" 6) ("CCDIQ" 127) ("UIQ" 24) ("CCUIQ" 15))

Architect, Registered NC, VA, SC, & GA.
Message 11 of 13
mracad
in reply to: dbroad

I was working on foreach foreach method and just couldn't work it out in my brain.

Long week....

Thanks

Message 12 of 13
dbroad
in reply to: mracad

You're welcome.  If you have the same number of elements and have them ordered specifically, then this is much faster:

 

(defun treecadr (lst);;DCBroad - return second elements only
  (if lst
    (cons (mapcar 'cadr (car lst))
	  (treecadr (cdr lst)))))

;;format (addstuff listx)
(defun addstuff2 (lst);;add special list
  (apply 'mapcar (cons '+ (treecadr(mapcar 'cadr lst)))))

 

Architect, Registered NC, VA, SC, & GA.
Message 13 of 13
phanaem
in reply to: mracad


@mracad wrote:

SORRY guys..I made a mistake with the list.

.......

would return

(60 15 6 127 24 15)


(apply 'mapcar (cons '+ (mapcar '(lambda (x) (mapcar 'cadr x)) (mapcar 'cadr ListX))))

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost