I had need to distil lists of a particular type of list structure down to grouped, sorted and unique values.
In the remote chance someone may have similar need, or want for idea fodder here be:
(defun _Distil ( lst / _Distinct _GetKeys _GetItems )
;; Example use:
;;
;; (_Distil
;; '(
;; ("KEY1" ("SUB3" "V3") ("SUB2" "V2") ("SUB1" "V1"))
;; ("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3")) ;; dup of 1st lst
;; ("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3")) ;; dup of 1st lst
;; ("KEY3" ("SUB2" "V8") ("SUB2" "V8") ("SUB2" "V8")) ;; has dup'd items
;; ("KEY2" ("SUB1" "V4") ("SUB2" "V5") ("SUB3" "V6"))
;; ("KEY2" ("SUB1" "V7") ("SUB1" "V7") ("SUB1" "V7")) ;; has dup'd items
;; )
;; )
;;
;; Result (grouped, sorted, unique values per group and sub group):
;;
;; (
;; ("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3"))
;; ("KEY2" ("SUB1" "V4" "V7") ("SUB2" "V5") ("SUB3" "V6"))
;; ("KEY3" ("SUB2" "V8"))
;; )
;;
;; Note: Intended for uniform keys and data types, will crash if they
;; vary. Easily remedied if one adds code to normalize the comparison
;; values in the sorting part of _Distinct but I didn't have need for
;; that in my application nor did I want the performance hit associated
;; with it.
;;
;; Simplistic, non robust solution to address the above:
;;
;; (defun _Distinct ( lst / result )
;; (mapcar 'cadr
;; (vl-sort
;; (progn
;; (foreach x lst
;; (if (not (member x result))
;; (setq result (cons x result))
;; )
;; )
;; (mapcar
;; (function
;; (lambda (x) (list (vl-princ-to-string x) x))
;; )
;; result
;; )
;; )
;; (function (lambda (a b) (< (car a) (car b))))
;; )
;; )
;; )
(defun _Distinct ( lst / result )
(vl-sort
(progn
(foreach x lst
(if (not (member x result))
(setq result (cons x result))
)
)
result
)
'<
)
)
(defun _GetKeys ( lst )
(_Distinct (mapcar 'car lst))
)
(defun _GetItems ( key lst )
(vl-remove-if-not
(function (lambda (x) (eq key (car x))))
lst
)
)
(mapcar
(function
(lambda (lst)
(cons (car lst)
(mapcar
(function
(lambda (sub_key)
(cons sub_key
(_Distinct
(mapcar 'cadr
(_GetItems sub_key (cdr lst))
)
)
)
)
)
(_GetKeys (cdr lst))
)
)
)
)
(mapcar
(function
(lambda (key)
(cons key
(apply 'append
(mapcar 'cdr
(_GetItems key lst)
)
)
)
)
)
(_GetKeys lst)
)
)
)
Example:
(_Distil
'(
("KEY1" ("SUB3" "V3") ("SUB2" "V2") ("SUB1" "V1"))
("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3")) ;; dup of 1st lst
("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3")) ;; dup of 1st lst
("KEY3" ("SUB2" "V8") ("SUB2" "V8") ("SUB2" "V8")) ;; has dup'd items
("KEY2" ("SUB1" "V4") ("SUB2" "V5") ("SUB3" "V6"))
("KEY2" ("SUB1" "V7") ("SUB1" "V7") ("SUB1" "V7")) ;; has dup'd items
)
)
Result (grouped, sorted, unique values per group and sub group):
(
("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3"))
("KEY2" ("SUB1" "V4" "V7") ("SUB2" "V5") ("SUB3" "V6"))
("KEY3" ("SUB2" "V8"))
)
FWIW ... Cheers.