Author Topic: Get TAG name List question  (Read 9038 times)

0 Members and 1 Guest are viewing this topic.

jaydee

  • Guest
Get TAG name List question
« on: July 28, 2011, 06:34:31 PM »
Hi.

I got this list. This is a flexible list which length varies and position of the filled value also varies.

(("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "ccc") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . ""))

What i would like to know is the last TAG name that has an attribute value and the first one has NO value.
In this case i want it to return TAG4 = "ddd" and TAG5 ""

This list below only happens lest then 1% of the time. which contain an unfill attribute value before the fill one.
(("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . ""))

Which i still want it to return return TAG4 = "ddd" and TAG5 ""

Thankyou in advance







Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: Get TAG name List question
« Reply #1 on: July 28, 2011, 07:12:22 PM »
Quick 'n Dirty:

Code: [Select]
(defun foo ( lst )
  (cond
    ( (null (cddr lst)) lst)
    ( (and
        (eq "" (cdadr  lst))
        (eq "" (cdaddr lst))
      )
      (list (car lst) (cadr lst))
    )
    ( (foo (cdr lst)) )
  )
)
Code: [Select]
_$ (foo '(("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "ccc") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . "")))
(("TAG4" . "ddd") ("TAG5" . ""))

_$ (foo '(("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . "")))
(("TAG4" . "ddd") ("TAG5" . ""))

jaydee

  • Guest
Re: Get TAG name List question
« Reply #2 on: July 28, 2011, 07:30:29 PM »
Thankyou Lee, You're the quickest.

Code: [Select]

_$ (foo '(("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "ccc") ("TAG4" . "ddd") ("TAG5" . "EEE") ("TAG6" . "FFF")))
(("TAG5" . "EEE") ("TAG6" . "FFF"))

_$ (foo '(("TAG1" . "aaa") ("TAG2" . "bbb") [color=red]("TAG3" . "") [/color] ("TAG4" . "ddd") ("TAG5" . "EEE") ("TAG6" . "FFF")))
(("TAG5" . "EEE") ("TAG6" . "FFF"))



I just test this list and if everything was filled or the last TAG was filled in and the result is not what i want,
the result i would like to see in both scenario is
(("TAG6" . "FFF"))

cheers
« Last Edit: July 28, 2011, 07:48:41 PM by jaydee »

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: Get TAG name List question
« Reply #3 on: July 28, 2011, 07:49:25 PM »
Quick mod:

Code: [Select]
(defun foo ( lst )
  (cond
    ( (null (cddr lst))
      (if (/= "" (cdadr lst)) (cdr lst) lst)
    )
    ( (and
        (eq "" (cdadr  lst))
        (eq "" (cdaddr lst))
      )
      (list (car lst) (cadr lst))
    )
    ( (foo (cdr lst)) )
  )
)

jaydee

  • Guest
Re: Get TAG name List question
« Reply #4 on: July 28, 2011, 08:19:21 PM »
Thanks Lee, Perfect.
I just want to learnt, do you mind explain to me how the FOO function works, just a few words in each line describing what it does?

Cheers

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: Get TAG name List question
« Reply #5 on: July 28, 2011, 08:34:19 PM »
The function 'foo' is tail-recursive; recursive in that the function calls itself from within its own function definition, and tail-recursive since there are no expressions to be evaluated following the recursive call.

This tail-recursive behaviour is better demonstrated using a trace call:

Code: [Select]
Entering (FOO (("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "ccc") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . "")))
  Entering (FOO (("TAG2" . "bbb") ("TAG3" . "ccc") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . "")))
    Entering (FOO (("TAG3" . "ccc") ("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . "")))
      Entering (FOO (("TAG4" . "ddd") ("TAG5" . "") ("TAG6" . "")))
      Result:  (("TAG4" . "ddd") ("TAG5" . ""))
    Result:  (("TAG4" . "ddd") ("TAG5" . ""))
  Result:  (("TAG4" . "ddd") ("TAG5" . ""))
Result:  (("TAG4" . "ddd") ("TAG5" . ""))

Notice that when the last recursive call is completed, the result follows all the way back up the stack and is returned. This thread is an interesting read on tail-recursion.

Here is a brief outline of the inner workings of the function:

Code: [Select]
(defun foo ( lst )
  (cond
    ( (null (cddr lst)) ;; two items in the list
      (if (/= "" (cdadr lst)) ;; second item is paired with non-empty string
        (cdr lst) ;; return last item
        lst ;; else return both items
      )     
    )
    ( (and
        (eq "" (cdadr  lst)) ;; second item is paired with empty string
        (eq "" (cdaddr lst)) ;; third item is paired with empty string
      )
      (list (car lst) (cadr lst)) ;; return first and second items
    )
    ( (foo (cdr lst)) ) ;; Else recursively process rest of list
  )
)

Note that an iterative function could also be written:

Code: [Select]
(defun foo_iter ( lst )
  (while
    (and (cddr lst)
      (not
        (and
          (eq "" (cdadr  lst))
          (eq "" (cdaddr lst))
        )
      )
    )
    (setq lst (cdr lst))
  )
  (if (/= "" (cdadr (setq lst (list (car lst) (cadr lst)))))
    (cdr lst)
    lst
  )
)

jaydee

  • Guest
Re: Get TAG name List question
« Reply #6 on: July 28, 2011, 08:57:25 PM »
Hi.
I would assume it would stop after it found the first EMPTY string, so where does the code say not to stop looking after the first empty string, and since it doen't stop at first empty string, then why does it stop when for agument sake if there are 2 empty string prior.
ie
(foo '(("TAG1" . "aaa") ("TAG2" . "bbb") ("TAG3" . "")  ("TAG33" . "")("TAG4" . "ddd") ("TAG5" . "EEE")("TAG6" . "")))
(("TAG2" . "bbb") ("TAG3" . ""))

cheers

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Get TAG name List question
« Reply #7 on: July 29, 2011, 03:55:07 AM »
What about this one?
Code: [Select]
(defun TagTest (lst / i)
  (list (setq i (car (reverse (vl-remove-if '(lambda (item) (eq (cdr item) "")) lst))))
        (cadr (member i lst))
  )
)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Get TAG name List question
« Reply #8 on: July 29, 2011, 04:10:13 AM »
Actually just though about what happens if there's 2 duplicate entries. In which case this should work better:
Code: [Select]
(defun TagTest (lst / i)
  (list (setq i (car (vl-remove-if '(lambda (item) (eq (cdr item) "")) (setq lst (reverse lst)))))
        (nth (1- (vl-position i lst)) lst)
  )
)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: Get TAG name List question
« Reply #9 on: July 29, 2011, 07:27:19 AM »
I would assume it would stop after it found the first EMPTY string, so where does the code say not to stop looking after the first empty string, and since it doen't stop at first empty string, then why does it stop when for agument sake if there are 2 empty string prior.

No, it will only stop if either there are only two items remaining in the list, or there are two consecutive empty strings.


Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: Get TAG name List question
« Reply #10 on: July 29, 2011, 07:50:59 AM »
Actually just though about what happens if there's 2 duplicate entries. In which case this should work better

Nice ideas Irne, this follows the same theme:

Code: [Select]
(defun foo ( lst / i )
  (setq i (length lst))
  (vl-some '(lambda ( x ) (setq i (1- i)) (/= "" (cdr x))) (reverse lst))
  (cond
    ( (= i (1- (length lst)))
      (list (last lst))
    )
    ( (list (nth i lst) (nth (1+ i) lst)) )
  )
)

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Get TAG name List question
« Reply #11 on: July 29, 2011, 08:01:12 AM »
Thanks! Or even more "simply" and not needing to reverse - just iterate from the back:
Code: [Select]
(defun TagTest1 (lst / n)
  (setq n (length lst))
  (while (and (> (setq n (1- n)) 0) (eq (cdr (nth n lst)) "")))
  (list (nth n lst) (nth (1+ n) lst))
)

Edit: Though looking at your latest code, I think yours would be just a tad faster!  :kewl:
« Last Edit: July 29, 2011, 08:10:57 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: Get TAG name List question
« Reply #12 on: July 29, 2011, 08:29:56 AM »
Edit: Though looking at your latest code, I think yours would be just a tad faster!  :kewl:

I doubt there would be very much in it  :wink:

Don't forget this condition though:

I just test this list and if everything was filled or the last TAG was filled in and the result is not what i want,
the result i would like to see in both scenario is
(("TAG6" . "FFF"))
:-)

jaydee

  • Guest
Re: Get TAG name List question
« Reply #13 on: July 29, 2011, 01:38:45 PM »
Thankyou Lee and Irneb.

These functions works perfect for me, as i mentioned that a empty string before the filled string only happens less then 1% of the time.

verymuch appriciated for your help.

jaydee

  • Guest
Re: Get TAG name List question
« Reply #14 on: July 31, 2011, 06:43:40 AM »
Hi.
I came across one little issue with the blank values
Not very often i get this, but it does happens that the blank values NOT REALLY BLANK (ie  spaces "", " ", "   "),
what make this so difficult is that its not consistent. ie blank with no space, blank with 1 or 2 or more spaces.
I tried to mod the (foo) function to include the "OR" operator, but it might not be able to cover all combinations.
So how would i make it foolproof regardless of blank values with spaces or not?

Code: [Select]

(defun foo ( lst )
  (cond
    ( (null (cddr lst))
      (if (or (/= "" (cdadr lst))
              (/= " " (cdadr lst))) (cdr lst) lst)
    )
    ( (or
       (and (eq "" (cdadr  lst)) (eq "" (cdaddr lst)))
       (and (eq " " (cdadr  lst)) (eq " " (cdaddr lst)))
      )

      (list (car lst) (cadr lst))
    )
    ( (foo (cdr lst)))
  )
)


Thankyou