Hello,
I got a situation when developing some routines with lists. I tried to solve it, but I couldn’t do it for several days. For example, there are some lists like below;
(((a b) (1 2 3)) ((c d) (1 2 3)) ((e f) (4 5 6)) ((g h) (1 2 3)) ((i j) (7 8 9 10)) ((k l) (1 2 3 4 5)) ...)
I want to get results with each frequency of second lists like below;
result1 : (((1 2 3) 3) ((4 5 6) 1) ((1 2 3 4 5) 1)...)
result2 : (((a b) (1 2 3)) ((c d) (1 2 3)) ((g h) (1 2 3)))
Sorting the lists are the most biggest challenge of my new geometric sover.
Thanks in advance.
Hi
For result1, you can use the following generic CountBy function
;; gc:CountBy ;; Counts the items of a list by the key generated by the specified function. ;; Returns a list of dotted pairs in which the first item is the key and the second the number of occurences. ;; ;; Arguments ;; fun : the key generator function ;; lst : the list to process (defun gc:CountBy (fun lst / key pair res) (setq fun (eval fun)) (foreach l lst (setq key (fun l) res (if (setq pair (assoc key res)) (subst (cons key (1+ (cdr pair))) pair res) (cons (cons key 1) res) ) ) ) )
(gc:CountBy 'cadr '(((a b) (1 2 3)) ((c d) (1 2 3)) ((e f) (4 5 6)) ((g h) (1 2 3)) ((i j) (7 8 9 10)) ((k l) (1 2 3 4 5))))
returns: (((1 2 3 4 5) . 1) ((7 8 9 10) . 1) ((4 5 6) . 1) ((1 2 3) . 3))
For result2, you can have a look at the vl-remove-if(-not) function.
(vl-remove-if-not
'(lambda (x) (equal (cadr x) '(1 2 3)))
'(((a b) (1 2 3)) ((c d) (1 2 3)) ((e f) (4 5 6)) ((g h) (1 2 3)) ((i j) (7 8 9 10)) ((k l) (1 2 3 4 5)))
)
returns: (((A B) (1 2 3)) ((C D) (1 2 3)) ((G H) (1 2 3)))
Or, use the following generic GroupBy function and deal with the returned list
;; Groups the items of a list by the key generated by the specified function. ;; Returns a list of lists in which the first item is the key. ;; ;; Arguments ;; fun : the key generator function ;; lst : the list to process (defun gc:GroupBy (fun lst / key sub res) (setq fun (eval fun)) (mapcar '(lambda (l) (cons (car l) (reverse (cdr l)))) (foreach l lst (setq res (if (setq sub (assoc (setq key (fun l)) res)) (subst (vl-list* key l (cdr sub)) sub res) (cons (list key l) res) ) ) ) ) )
(setq groupedList (gc:GroupBy 'cadr '(((a b) (1 2 3)) ((c d) (1 2 3)) ((e f) (4 5 6)) ((g h) (1 2 3)) ((i j) (7 8 9 10)) ((k l) (1 2 3 4 5)))))
returns:
(
((1 2 3 4 5) ((K L) (1 2 3 4 5)))
((7 8 9 10) ((I J) (7 8 9 10)))
((4 5 6) ((E F) (4 5 6)))
((1 2 3) ((A B) (1 2 3)) ((C D) (1 2 3)) ((G H) (1 2 3)))
)
You can also get result1 from the list returned by gc:GroupBy:
(setq result1 (mapcar '(lambda (x) (cons (car x) (length (cdr x)))) groupedList))