Jump to content

Create a list from a loop


saim

Recommended Posts

I have a "foreach" loop running through a list and want a list of the returned values. But I can't seem to work it out and I don't know why.

First, before the loop, I create the list with one element to be deleted later (and would appreciate if someone showed me a way to get rid of this add-and-get-rid)

Then, I run the loop, appending the results to the list.

After the loop, I replace the list with a copy of it without the first element.

 

Here's a similar code, with the same problem. I'm probably doing something wrong...

 

(defun c:testaforeach()
    (setq listappend (list 1 2 3 4 5));a list with elements to be appended
    (setq list1 (list 0)); starts the list
    (foreach e listappend
        (append list1 (list e)); appends a list containig just that element to the started one
        (print e)
    )
    (setq list1 (cdr list1)) ; get rid of the first element
)

 

What I'm getting is an nil value. the print command does print it all, but the list is still empty. :(

Why doesn't the "list1" end up as the "listappend" started?
I can show all the real code, if necessary, but I believe the core of the problem is the syntax used here.

 

Edit: Solved. It WAS the syntax. Sorry for posting and figuring out on my own, right after (is there a way to delete this topic?)...

Here's the fixed code

(defun c:testaforeach()
    (setq listappend (list 1 2 3 4 5));a list with elements to be appended
    (setq list1 (list 0)); starts the list
    (foreach e listappend
        (setq list1 (append list1 (list e))); appends a list containig just that element to the started one
        (print e)
    )
    (setq list1 (cdr list1)) ; get rid of the first element
)


 

Edited by saim
Link to comment
Share on other sites


(setq l '(0 1 2 3 4 5))

(defun _cdr (l n) 
  (if (> n 0)(cons (nth (1- n) l) (_cdr l (1- n))))
    )

(_cdr (reverse l) (1-(length l))) 
;(1 2 3 4 5) 

(_cdr (reverse l) 3 ) 
;(3 4 5) 

 

  • Like 1
Link to comment
Share on other sites

For what it's worth, note that you don't need to 'start the list', as nil is equivalent to an empty list in AutoLISP, and an unbound symbol will similarly evaluate to nil and hence an empty list.

 

As such, your code could be written as:

(defun c:test1 ( / mylist mynewlist )
    (setq mylist '(0 1 2 3 4 5))
    (foreach x mylist
        (setq mynewlist (append mynewlist (list x)))
        (print x)
    )
    (setq mynewlist (cdr mynewlist))
)

Testing the above yields the following at the Visual LISP IDE console:

_$ (c:test1)

0 
1 
2 
3 
4 
5 (1 2 3 4 5)

Be sure to declare your local variables within the defun expression, otherwise the variables will be considered global and will retain their values within the document namespace (i.e. within the scope of the active drawing) - observe:

(defun c:test2 ( ) ;; No local variables - all variables are global!
    (setq mylist '(0 1 2 3 4 5))
    (foreach x mylist
        (setq mynewlist (append mynewlist (list x)))
        (print x)
    )
    (setq mynewlist (cdr mynewlist))
)
_$ (c:test2)

0 
1 
2 
3 
4 
5 (1 2 3 4 5)
_$ (c:test2)

0 
1 
2 
3 
4 
5 (2 3 4 5 0 1 2 3 4 5)

Notice how the list contents are repeated for every evaluation (and incorrect values removed by the cdr expression) because the mynewlist variable has retained its value after the function has completed evaluation? For more information on this concept, you may wish to refer to my Localising Variables tutorial.

 

I would also suggest the use of the AutoLISP cons function, as this is both cleaner and more efficient than the append function:

(defun c:test3 ( / mylist mynewlist )
    (setq mylist '(0 1 2 3 4 5))
    (foreach x mylist
        (setq mynewlist (cons x mynewlist))
        (print x)
    )
    (setq mynewlist (cdr (reverse mynewlist)))
)
_$ (c:test3)

0 
1 
2 
3 
4 
5 (1 2 3 4 5)

In this case, since elements are 'pushed' onto the front of the list, the list is therefore constructed in reverse and the reverse function is used at the end of the function.

 

Edited by Lee Mac
  • Like 1
Link to comment
Share on other sites

Thanks for the tips!

I didn't know the "cons" command. It's really nicer than "append", in some cases. Thank you both for that!
What does "cons" stand for? Knowing it will help me to remember the command.

 

I'm aware of the advantages of declaring the variables. I just need to make them global during the debug, to check the resulting value - I often make mistakes, checking the result helps to find out what has been done wrong. But you're right, I had problems alike the very example you gave and fixed it declaring the variable as local, so kudos for you! :)

 

Now, for the 'start the list' thing... I see AutoLisp taking an empty space, saying "this is an empty list" and adding elements to it. Doesn't... fell right. Maybe because I couldn't translate the "unbound symbol" expression you used. Could you explain what does it mean?

Link to comment
Share on other sites

29 minutes ago, saim said:

 

I didn't know the "cons" command. It's really nicer than "append", in some cases. Thank you both for that!

 

Typically one constructs a list per iteration, using the cons function, just like in Lee Mac's demo.

While append may be used within conditional statements, in order to either append the item into the list or not - simulating a void (void != null) :

 

; (testappend) >> (0 1 2 4 5)
(defun testappend ( / mynewlist ) 
  (foreach x '(0 1 2 3 4 5)
    (setq mynewlist (append mynewlist (if (/= x 3) (list x))))
  )
  mynewlist
)

; (testcons) >> (0 1 2 nil 4 5)
(defun testcons ( / mynewlist ) 
  (foreach x '(0 1 2 3 4 5)
    (setq mynewlist (cons  (if (/= x 3) x) mynewlist))
  )
  (reverse mynewlist)
)

 

40 minutes ago, saim said:

I'm aware of the advantages of declaring the variables.

 

Its not an advantage, its a requirement! See this.

 

 

41 minutes ago, saim said:

I just need to make them global during the debug, to check the resulting value

See this.

 

 

42 minutes ago, saim said:

so kudos for you!

You may use the "like button", this is the facebook of CAD people! :lol:

 

44 minutes ago, saim said:

I see AutoLisp taking an empty space, saying "this is an empty list" and adding elements to it. Doesn't... fell right. Maybe because I couldn't translate the "unbound symbol" expression you used

 

Ok, starting simple:

MyList >> nil
(cons "MyItem" nil) >> ("MyItem")
(setq MyList (cons "MyItem" MyList)) >> ("MyItem")
(setq MyList (cons "MySecondItem" MyList)) >> ("MySecondItem" "MyItem")
(setq MyList (cons "MyThirdItem" MyList)) >> ("MyThirdItem" "MySecondItem" "MyItem")

If something doesn't work as you've expected or you don't understand how its working, then build your facts and knowledge upon observations.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...