 # Loop while with Nested Lists / Python

Trying to loop a list of two lines based on randomly generated points.
Within a rectangular boundary from (0,0,0) to (10,10,0) both lines should be longer than 12. The shorter line being only 3.86 long, the loop obviously doesn’t work with the list.
Can anyone tell me what’s wrong with the code?

However with only one random line, i.e. without using a list, the loop, though not being very fast, works.

I tried a similar example using AutoCAD and VB.NET, where loop calculation seemed to be much faster.
Why is this?

= = = = =
Loop while code for list
= = = = =

geometry = [Imperative]
{
// use range expressions to generate collection of numbers
nums1x = {Math.Random (0, 10), Math.Random (0, 10)};
nums1y = {Math.Random (0, 10), Math.Random (0, 10)};
nums2x = {Math.Random (0, 10), Math.Random (0, 10)};
nums2y = {Math.Random (0, 10), Math.Random (0, 10)};
// use the collections of numbers to generate collections of points
points1 = Point.ByCoordinates(nums1x, nums1y, 0);
points2 = Point.ByCoordinates(nums2x, nums2y, 0);
// use the collections of points to generate a collection of lines
lines = Line.ByStartPointEndPoint(points1, points2);
// generate a list of line lengths
list1 = lines.Length;
// generate the minimum length within the list
list1min = List.MinimumItem(list1);

// loop while length is smaller than …
while (list1min < 12)
{
nums1x = {Math.Random (0, 10), Math.Random (0, 10)};
nums1y = {Math.Random (0, 10), Math.Random (0, 10)};
nums2x = {Math.Random (0, 10), Math.Random (0, 10)};
nums2y = {Math.Random (0, 10), Math.Random (0, 10)};
points1 = Point.ByCoordinates(nums1x, nums1y, 0);
points2 = Point.ByCoordinates(nums2x, nums2y, 0);
lines = Line.ByStartPointEndPoint(points1, points2);
list1 = lines.Length;
list1min = List.MinimumItem(list1);
}
return = lines;
};

I suspect your problem indeed arises from the x1 = {randomx , randomx}.
But why do you want to do that in the first place?

All your nums vars are lists of 2 items.
You then generate 2 lists of 2 points called points1 and points2.
I don’t know how dynamy handles this but at the last part, you’re calling “MinimumItem” on a list of lists of lengths. Not a list of lengths.

Perhaps you’re going to need to flatten both lists before you do your “minimumitem” , but I highly recommend against doing this as it’s rather unconventional and a bit redundant.

I don’t think replication works in imperative blocks. (calling a function which accepts one type of argument and dynamo figuring out how to apply that function to your inputs of different types) like your call to Line.ByStartPointEndPoint - that function takes 2 point parameters, but you’re calling it with two lists. I don’t think this works inside an imperative block.

Replication apparently not working within imperatve code blocks, I’ll try it using Python.

once you are in an imperative block you’re going to be need to use things like list.map, and loops to achieve behavior that replication gave you outside.

Meanwhile I tried it in Python where looping works for two lines.
To reduce the number of operations lines do start in the bottom (0<y<50) and do end in the upper half (51<y<100) of the restricting square (100 x 100 x 0).

But how about something like “nested lists” in Python?
In Dynamo, where multiple looping didn’t work in the code block, it was however possible to create a “list of lines” from a “list of points” from a “list of numbers”:

= DYNAMO CODE =
points1 = Point.ByCoordinates(nums1x, nums1y, 0); / points2 = Point.ByCoordinates(nums2x, nums2y, 0);
lines = Line.ByStartPointEndPoint(points1, points2);
= = =

Is there any comparable “nested” code in Python?

I think you are asking if python can do replication? You can kind of use list comprehensions for this in python.

Normal python execution is like the imperative execution from DesignScript. To call functions with items from a list you need to use an iteration mechanism like mapping, or iterating with a loop.

You could do something like this: ``````import clr
from Autodesk.DesignScript.Geometry import *
import sys
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')
import random
minlength = 0
n=0
lines = []
linenum = IN
while minlength < 100 or n < linenum:
p1 = Point.ByCoordinates(random.randint(1,100),random.randint(1,50),0)
p2 = Point.ByCoordinates(random.randint(1,100),random.randint(51,100),0)
p3 = Point.ByCoordinates(random.randint(1,100),random.randint(1,50),0)
p4 = Point.ByCoordinates(random.randint(1,100),random.randint(51,100),0)
L1 = Line.ByStartPointEndPoint(p1,p2)
L2 = Line.ByStartPointEndPoint(p3,p4)
list = (L1.Length, L2.Length)
minlength = min(list)
if minlength > 100:
lines.append([L1,L2])
n = n+1
else:
pass
#Assign your output to the OUT variable.
OUT = lines``````
3 Likes

Just tried out what Jonathan suggested and it works.
I idid also simplify the code so there is only one list to which new lines are added one by one instead of adding pairs of lines.

Needed this sample to check the calculation speed for random based looping.
But even with 1000 lines and tighter geometric restrictions Python seems to be quite fast with it.

Thank you all for your hints!

1 Like

Now that you have that code working I would be interested if you have any trouble back converting it to DS?

I’ve not tried to achieve the same result using an imperative DS code block yet.
Also thought about building a DS function with the same content instead of an imperative DS code block…