Author Topic: List processing, distillage  (Read 1920 times)

0 Members and 1 Guest are viewing this topic.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
List processing, distillage
« on: January 30, 2014, 02:24:56 PM »
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:

Code: [Select]
(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:

Code: [Select]
(_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):

Code: [Select]
(
   ("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3"))
   ("KEY2" ("SUB1" "V4" "V7") ("SUB2" "V5") ("SUB3" "V6"))
   ("KEY3" ("SUB2" "V8"))
)

FWIW ... Cheers.
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: List processing, distillage
« Reply #1 on: January 30, 2014, 05:27:46 PM »
Thanks for sharing MP - this would make a good 'challenge' thread  :-)

To expand on your idea, here are two variations of a function to perform the same operation on lists of any nesting depth:

Code: [Select]
(defun _distil2 ( lst / foo rtn )

    (defun foo ( lst / tmp1 tmp2 x1 )
        (if (setq x1 (caar lst))
            (progn
                (foreach x2 lst
                    (if (= x1 (car x2))
                        (setq tmp1 (cons (cdr x2) tmp1))
                        (setq tmp2 (cons x2 tmp2))
                    )
                )
                (cons (cons x1 (_distil2 (apply 'append tmp1))) (foo tmp2))
            )
        )
    )

    (if (listp (car lst))
        (vl-sort (foo lst) '(lambda ( a b ) (< (car a) (car b))))
        (progn
            (foreach itm lst
                (if (not (member itm rtn))
                    (setq rtn (cons itm rtn))
                )
            )
            (vl-sort rtn '<)
        )
    )
)

Code: [Select]
(defun _distil3 ( lst / itm rtn tmp )
    (if (= 'list (type (car lst)))
        (progn
            (foreach grp lst
                (if (setq itm (assoc (car grp) tmp))
                    (setq tmp (subst (cons (car grp) (append (cdr itm) (cdr grp))) itm tmp))
                    (setq tmp (cons grp tmp))
                )
            )
            (foreach grp tmp
                (setq rtn (cons (cons (car grp) (_distil3 (cdr grp))) rtn))
            )
            (vl-sort rtn '(lambda ( a b ) (< (car a) (car b))))
        )
        (progn
            (foreach itm lst
                (if (not (member itm rtn))
                    (setq rtn (cons itm rtn))
                )
            )
            (vl-sort rtn '<)
        )
    )
)

Example with your list:
Code: [Select]
(_distil2
   '(
        ("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
    )
)
Code: [Select]
(
    ("KEY1" ("SUB1" "V1") ("SUB2" "V2") ("SUB3" "V3"))
    ("KEY2" ("SUB1" "V4" "V7") ("SUB2" "V5") ("SUB3" "V6"))
    ("KEY3" ("SUB2" "V8"))
)

Example using a list with one level of nesting:
Code: [Select]
(_distil2
   '(
        ("KEY1" "V3" "V2" "V1")
        ("KEY1" "V1" "V2" "V3")
        ("KEY1" "V1" "V2" "V3")
        ("KEY3" "V8" "V8" "V8")
        ("KEY2" "V4" "V5" "V6")
        ("KEY2" "V7" "V7" "V7")
    )
)
Code: [Select]
(
    ("KEY1" "V1" "V2" "V3")
    ("KEY2" "V4" "V5" "V6" "V7")
    ("KEY3" "V8")
)

Example with three levels of nesting:
Code: [Select]
(_distil2
   '(
        ("KEY1"
            ("SUB3"
                ("SUBSUB1" "V3")
                ("SUBSUB1" "V4")
                ("SUBSUB2" "V5")
            )
            ("SUB2"
                ("SUBSUB3" "V3")
                ("SUBSUB1" "V6")
                ("SUBSUB2" "V6")
            )
            ("SUB1"
                ("SUBSUB3" "V3")
                ("SUBSUB1" "V6")
                ("SUBSUB1" "V6")
            )
        )
        ("KEY2"
            ("SUB3"
                ("SUBSUB1" "V3")
                ("SUBSUB1" "V4")
                ("SUBSUB2" "V5")
            )
            ("SUB2"
                ("SUBSUB3" "V3")
                ("SUBSUB1" "V6")
                ("SUBSUB2" "V6")
            )
            ("SUB1"
                ("SUBSUB3" "V3")
                ("SUBSUB1" "V6")
                ("SUBSUB1" "V6")
            )
        )
        ("KEY2"
            ("SUB3"
                ("SUBSUB1" "V3")
                ("SUBSUB1" "V4")
                ("SUBSUB2" "V5")
            )
            ("SUB2"
                ("SUBSUB3" "V3")
                ("SUBSUB1" "V6")
                ("SUBSUB2" "V6")
            )
            ("SUB1"
                ("SUBSUB3" "V3")
                ("SUBSUB1" "V6")
                ("SUBSUB1" "V6")
            )
        )
    )
)
Code: [Select]
(
    ("KEY1"
        ("SUB1" ("SUBSUB1" "V6") ("SUBSUB3" "V3"))
        ("SUB2" ("SUBSUB1" "V6") ("SUBSUB2" "V6") ("SUBSUB3" "V3"))
        ("SUB3" ("SUBSUB1" "V3" "V4") ("SUBSUB2" "V5"))
    )
    ("KEY2"
        ("SUB1" ("SUBSUB1" "V6") ("SUBSUB3" "V3"))
        ("SUB2" ("SUBSUB1" "V6") ("SUBSUB2" "V6") ("SUBSUB3" "V3"))
        ("SUB3" ("SUBSUB1" "V3" "V4") ("SUBSUB2" "V5"))
    )
)

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: List processing, distillage
« Reply #2 on: January 30, 2014, 08:18:02 PM »
Great work Lee, thanks for blessing the thread with your code & ideas.
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

fixo

  • Guest
Re: List processing, distillage
« Reply #3 on: January 31, 2014, 04:29:36 AM »
I'm too late probably,
here is one from my sorting library

Code: [Select]
(defun group_uniques  (lst / itm res tmp)
  (defun unique (lst / result)
;; borrowed from CAB
    (reverse
      (while (setq itm (car lst))
(setq lst    (vl-remove itm lst)
      result (cons itm result)))))
;;main func
  (while
    (setq tmp (vl-remove-if
'(lambda (x)
   (and (not (equal (car x) (caar lst) 1e-09)) x))
lst))
     (setq res (append res
       (list
(cons (caar tmp)
       (unique
(vl-sort (apply 'append
(mapcar 'cdr tmp))
  '(lambda (a b)
     (and (< (car a) (car b)) (< (cadr a) (cadr b))))
  ))))))
     (setq lst (vl-member-if-not '(lambda (a) (member a tmp)) lst)))
  res
  )

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: List processing, distillage
« Reply #4 on: February 01, 2014, 11:44:25 AM »
Great work Lee, thanks for blessing the thread with your code & ideas.

Thank you Michael, it was very enjoyable to write  :-)