Make a list of products and quantities from a list of dotted pairs

Make a list of products and quantities from a list of dotted pairs

mid-awe
Collaborator Collaborator
415 Views
6 Replies
Message 1 of 7

Make a list of products and quantities from a list of dotted pairs

mid-awe
Collaborator
Collaborator

Please help, I am having a dumb moment and becoming exasperated.

 

I have a list of pairs,

(("372" .  "8LG")  ("373" .  "4LG") ("374" .  "1LG")  ("375" .  "no equiv") ("376" .  "4LG") )

 

What I need is to total up each CDR value, then produce a new list like:

(("1" .  "1LG")("2" . "4LG")("1" . "8LG")("1" . "no equiv"))

 

Please help, I know this shouldn't be difficult but the solution evades me.

 

Thank you in advance for any help or suggestions.

0 Likes
Accepted solutions (1)
416 Views
6 Replies
Replies (6)
Message 2 of 7

ВeekeeCZ
Consultant
Consultant

Possibly like this

 

(defun test (lst / l a )
  (foreach e (vl-sort (mapcar 'cdr lst) '>)
    (setq l (if (setq a (assoc e l))
	      (subst (cons e (1+ (cdr a))) a l)
	      (cons (cons e 1) l))))
  (mapcar '(lambda (e) (cons (itoa (cdr e)) (car e))) l))

 

Message 3 of 7

mid-awe
Collaborator
Collaborator

Thank you, I have another challenge, I am trying to use VL-STRING-SEARCH  to find "no equiv" as it is attached to the end of the unmatchable sku# like this ("5" . "J-LG-1P-25-NO-CL090-DW <- no equiv")

 

To adjust the code you shared I did this:

 

(foreach e (vl-sort (mapcar 'cdr lst) '>)
(IF (= nil (VL-STRING-SEARCH "<- no equiv" e))
(setq l (if (setq a (assoc e l))
(subst (cons e (1+ (cdr a))) a l)
(cons (cons e 1) l)))))

 

But of course, everything goes haywire. By haywire I mean, it takes this list:

 

(("9" . "J-LG-1P-50-NO-CL180-DW <- no equiv") ("8" . "J-LG-1P-50-NO-CL180-DW <- no equiv") ("7" . "J-LG-1P-50-NO-CC180-DW <- no equiv") ("6" . "5LG") ("5" . "J-LG-1P-50-NO-CL180-DW <- no equiv") ("4" . "4LG") ("3" . "4LG") ("20" . "4LG") ("2" . "4LG") ("19" . "J-LG-1P-25-NO-CL090-DW <- no equiv") ("18" . "4LG") ("17" . "4LG") ("16" . "4LG") ("15" . "10LG") ("14" . "10LG") ("13" . "5LG") ("12" . "4LG") ("11" . "4LG") ("10" . "J-LG-1P-50-NO-CC180-DW <- no equiv") ("1" . "J-LG-1P-50-NO-CC180-DW <- no equiv"))

 

and returned this,

 

(("1" . "10LG") ("1" . "4LG") ("1" . "5LG") ("1" . "no equiv") ("1" . "no equiv") ("1" . "no equiv") ("1" . "no equiv") ("1" . "no equiv") ("1" . "no equiv") ("1" . "no equiv"))

 

but I was hoping for this:

 

(("7" . "no equiv") ("2" . "5LG") ("9" . "4LG") ("2" . "10LG"))

 

I hope that makes sense.

 

Thank you for your help.

0 Likes
Message 4 of 7

komondormrex
Mentor
Mentor

try the following

(defun parse_list (_list / unique_list old_member)
	(foreach _member _list (if (not (member _member unique_list)) (setq unique_list (append unique_list (list _member)))))
	(setq unique_list (mapcar '(lambda (_member) (cons _member 0)) unique_list))
	(foreach _member _list
		(if (setq old_member (assoc _member unique_list))
				(setq unique_list (subst (cons (car old_member) (1+ (cdr old_member))) old_member unique_list))
		)
	)
)

(setq assoc_list '(("9" . "J-LG-1P-50-NO-CL180-DW <- no equiv") ("8" . "J-LG-1P-50-NO-CL180-DW <- no equiv") ("7" . "J-LG-1P-50-NO-CC180-DW <- no equiv") ("6" . "5LG") ("5" . "J-LG-1P-50-NO-CL180-DW <- no equiv") ("4" . "4LG") ("3" . "4LG") ("20" . "4LG") ("2" . "4LG") ("19" . "J-LG-1P-25-NO-CL090-DW <- no equiv") ("18" . "4LG") ("17" . "4LG") ("16" . "4LG") ("15" . "10LG") ("14" . "10LG") ("13" . "5LG") ("12" . "4LG") ("11" . "4LG") ("10" . "J-LG-1P-50-NO-CC180-DW <- no equiv") ("1" . "J-LG-1P-50-NO-CC180-DW <- no equiv")))

 

(parse_list (mapcar '(lambda (element) (if (wcmatch (cdr element) "*no equiv*") "no equiv" (cdr element))) assoc_list)) -> (("no equiv" . 7) ("5LG" . 2) ("4LG" . 9) ("10LG" . 2))

Message 5 of 7

ВeekeeCZ
Consultant
Consultant
Accepted solution

Well, I would suggest to break down process to small steps which should make the process easier. Also added the comments to help understand. IMHO that main sort algoritmem based on an associated list - that is very common algorithm, very useful, you should really try to learn and understand.

 

(defun test (lst / l a )

    ;; prepare the list...
    
    (setq lst (mapcar 'cdr lst)) 	; make a list of second items
    
    (setq lst (mapcar '(lambda (e)	; clear the list
			 (if (vl-string-search "<- no equiv" e)
			   "<- no equiv"
			   e)
			 )
		      lst))
    
    ;; use an associate list to count unique items... '((unique-item1 . total1) (unique-item2 . total2) (unique-item3 . total3) ...)
    
    (foreach e lst
      (if (setq a (assoc e l))				; if item already is in the new l list
	(setq l (subst (cons e (1+ (cdr a)))		; then replace item with new one that addes +1 to total (item . (+ 1 total))
		       a
		       l))
	(setq l (cons (cons e 1)			; else add new '(item . 1) to the list
		      l))))

    
    ;; restructure the list to desired output form

    (setq l (vl-sort l '(lambda (e1 e2) (> (car e1) (car e2))))) ; sort the list
    
    (mapcar '(lambda (e) (cons (itoa (cdr e)) (car e))) l)  	 ; reverse items, convert to string: from '(item . total) to ("total" . item)
    )

 

 

And to just fix your idea.. it's also possible.. 

 

(defun test (lst / l a )
    (foreach e (vl-sort (mapcar 'cdr lst) '>)

      (IF (VL-STRING-SEARCH "<- no equiv" e)
	(setq e "<- no equiv"))
      
      (setq l (if (setq a (assoc e l))
		(subst (cons e (1+ (cdr a))) a l)
		(cons (cons e 1) l))))
    (mapcar '(lambda (e) (cons (itoa (cdr e)) (car e))) l))

 

Message 6 of 7

mid-awe
Collaborator
Collaborator

Thank you.

0 Likes
Message 7 of 7

mid-awe
Collaborator
Collaborator

Thank you for the detailed answer.

(mapcar 'cdr lst)

I missed this by a mile. You are always so generous with your answer. Again Thank you.

0 Likes