discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

for() loop iteration limitation & list comprehensions

JD
Jerry Davis
Thu, Mar 9, 2017 11:00 AM

Haven't really been following this too much.
But have you tried solidpython?
It produces ugly code, as you might imagine, but everything I have done so
far, works.

--
Extra Ham Operator: K7AZJ
Registered Linux User: 275424
Raspberry Pi and Openscad developer

The most exciting phrase to hear in science - the one that heralds new
discoveries - is not "Eureka!" but "That's funny...".
- Isaac. Asimov

On Thu, Mar 9, 2017 at 3:17 AM, nop head nop.head@gmail.com wrote:

I think this a work around that will allow a for loop of 10,000,000

module for_n(n) {
thousands = floor(n / 1000);
remainder = n % 1000;
if(thousands)
for(a = [0 : thousands - 1], b = [0 : 999], $i = a * 1000 + b)
children();
if(remainder)
for(a = [0 : remainder - 1], $i = thousands * 1000 + a)
children();
}

for_n(1002)
echo($i);

Note that it counts from 0 to n-1

On 9 March 2017 at 04:41, David Coneff david.coneff@gmail.com wrote:

Ronaldo,

Since you knew the for() syntax that bypasses the 10,000 element
limitation, I was wondering if you might also know the solution to this:

Say I have a list of the form:

[[x,y,z],[x2,y2,z2],....]

How would I make a for() loop that performs an action using the (i)-th
and (i+1)th elements? Normally I would use the iterator variable, but the
syntax that bypasses the 10,000 range limit doesn't have "access" to an
iterator variable.

simple example of what I would normally do:

points = [[1,1,1],[2,2,2],[3,3,3]]
for(i = [0:1:len(points-2)]){
translate([points[i][0],points[i+1][1],0])cube(1);
}

On Wed, Mar 8, 2017 at 3:54 PM, Ronaldo Persiano rcmpersiano@gmail.com
wrote:

David,

The main aspect to understand is that there is a for limit just for
ranges.

If you don't use range in a for, there is no limit.

p = rands(0,1,1000000); // p is a list of 1000000 elements
for(pi=p){ // there is no range here
if(pi<1e-6) echo(pi=pi);
}

Or if all your ranges have less than 10000 elements, you will not get an
error message.

// a very long for with ranges
for(i=[0:999], j=[0:999], k=1000*i+j){
if(k<10 ||  k> 999990) echo(k=k);
}

The same happens with for in list comprehension:

// short lists filtered from a long lists
q = [for(pi=p) if(pi<1e-6) pi];
s = [for(i=[0:999], j=[0:999], k=1000*i+j) if(k<len(p)-1 && p[k]<1e-6 )
p[k] ];
echo(q=q);
echo(s=s);


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Haven't really been following this too much. But have you tried solidpython? It produces ugly code, as you might imagine, but everything I have done so far, works. -- Extra Ham Operator: K7AZJ Registered Linux User: 275424 Raspberry Pi and Openscad developer *The most exciting phrase to hear in science - the one that heralds new discoveries - is not "Eureka!" but "That's funny...".*- Isaac. Asimov On Thu, Mar 9, 2017 at 3:17 AM, nop head <nop.head@gmail.com> wrote: > I think this a work around that will allow a for loop of 10,000,000 > > module for_n(n) { > thousands = floor(n / 1000); > remainder = n % 1000; > if(thousands) > for(a = [0 : thousands - 1], b = [0 : 999], $i = a * 1000 + b) > children(); > if(remainder) > for(a = [0 : remainder - 1], $i = thousands * 1000 + a) > children(); > } > > for_n(1002) > echo($i); > > Note that it counts from 0 to n-1 > > On 9 March 2017 at 04:41, David Coneff <david.coneff@gmail.com> wrote: > >> Ronaldo, >> >> Since you knew the for() syntax that bypasses the 10,000 element >> limitation, I was wondering if you might also know the solution to this: >> >> Say I have a list of the form: >> >> [[x,y,z],[x2,y2,z2],....] >> >> How would I make a for() loop that performs an action using the (i)-th >> and (i+1)th elements? Normally I would use the iterator variable, but the >> syntax that bypasses the 10,000 range limit doesn't have "access" to an >> iterator variable. >> >> simple example of what I would normally do: >> >> points = [[1,1,1],[2,2,2],[3,3,3]] >> for(i = [0:1:len(points-2)]){ >> translate([points[i][0],points[i+1][1],0])cube(1); >> } >> >> On Wed, Mar 8, 2017 at 3:54 PM, Ronaldo Persiano <rcmpersiano@gmail.com> >> wrote: >> >>> David, >>> >>> The main aspect to understand is that there is a for limit just for >>> ranges. >>> >>> If you don't use range in a for, there is no limit. >>> >>> p = rands(0,1,1000000); // p is a list of 1000000 elements >>> for(pi=p){ // there is no range here >>> if(pi<1e-6) echo(pi=pi); >>> } >>> >>> Or if all your ranges have less than 10000 elements, you will not get an >>> error message. >>> >>> // a very long for with ranges >>> for(i=[0:999], j=[0:999], k=1000*i+j){ >>> if(k<10 || k> 999990) echo(k=k); >>> } >>> >>> The same happens with for in list comprehension: >>> >>> // short lists filtered from a long lists >>> q = [for(pi=p) if(pi<1e-6) pi]; >>> s = [for(i=[0:999], j=[0:999], k=1000*i+j) if(k<len(p)-1 && p[k]<1e-6 ) >>> p[k] ]; >>> echo(q=q); >>> echo(s=s); >>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> Discuss@lists.openscad.org >>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >>> >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> >> > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
RP
Ronaldo Persiano
Thu, Mar 9, 2017 3:08 PM

David,

You may use nophead's code to do your job or you can code the for directly
as in:

p = rands(0,1,100005); // list generation
for( n = floor(len(p)/1000),
k = [0:n],
j = [0:k<n? 999 : len(p)%1000-1 ] ,
i = k*1000 + j )
echo(i,p[i]);

Note that this for will iterate until len(p)-1. To go until len(p)-2 change
len(p)%1000-1 to len(p)%1000-2 .

But the simplest form to solve your problem is to use the dev snapshot with
the C-like for() enabled.

for(i=[for(j=0; j<len(p); j=j+1) j]) {/* do what you want with p[i] */ }

for(i=[for(j=0; j<len(p)-1; j=j+1) j]) {/* do what you want with p[i] and
p[i+1] */ }

These forms of for() work just in list comprehension expressions.

David, You may use nophead's code to do your job or you can code the for directly as in: p = rands(0,1,100005); // list generation for( n = floor(len(p)/1000), k = [0:n], j = [0:k<n? 999 : len(p)%1000-1 ] , i = k*1000 + j ) echo(i,p[i]); Note that this for will iterate until len(p)-1. To go until len(p)-2 change len(p)%1000-1 to len(p)%1000-2 . But the simplest form to solve your problem is to use the dev snapshot with the C-like for() enabled. for(i=[for(j=0; j<len(p); j=j+1) j]) {/* do what you want with p[i] */ } for(i=[for(j=0; j<len(p)-1; j=j+1) j]) {/* do what you want with p[i] and p[i+1] */ } These forms of for() work just in list comprehension expressions.
NH
nop head
Thu, Mar 9, 2017 3:38 PM

That goes wrong when len(p) is a multiple of 1000 because for doesn't like
an end that is less that the start.

ECHO: 999, 0.997965

DEPRECATED: Using ranges of the form [begin:end] with begin value greater
than the end value is deprecated.

ECHO: 999, 0.997965

ECHO: 1000, undef

My version checked for that.

On 9 March 2017 at 15:08, Ronaldo Persiano rcmpersiano@gmail.com wrote:

David,

You may use nophead's code to do your job or you can code the for directly
as in:

p = rands(0,1,100005); // list generation
for( n = floor(len(p)/1000),
k = [0:n],
j = [0:k<n? 999 : len(p)%1000-1 ] ,
i = k*1000 + j )
echo(i,p[i]);

Note that this for will iterate until len(p)-1. To go until len(p)-2
change len(p)%1000-1 to len(p)%1000-2 .

But the simplest form to solve your problem is to use the dev snapshot
with the C-like for() enabled.

for(i=[for(j=0; j<len(p); j=j+1) j]) {/* do what you want with p[i] */ }

for(i=[for(j=0; j<len(p)-1; j=j+1) j]) {/* do what you want with p[i] and
p[i+1] */ }

These forms of for() work just in list comprehension expressions.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

That goes wrong when len(p) is a multiple of 1000 because for doesn't like an end that is less that the start. ECHO: 999, 0.997965 DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated. ECHO: 999, 0.997965 ECHO: 1000, undef My version checked for that. On 9 March 2017 at 15:08, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > David, > > You may use nophead's code to do your job or you can code the for directly > as in: > > p = rands(0,1,100005); // list generation > for( n = floor(len(p)/1000), > k = [0:n], > j = [0:k<n? 999 : len(p)%1000-1 ] , > i = k*1000 + j ) > echo(i,p[i]); > > Note that this for will iterate until len(p)-1. To go until len(p)-2 > change len(p)%1000-1 to len(p)%1000-2 . > > But the simplest form to solve your problem is to use the dev snapshot > with the C-like for() enabled. > > for(i=[for(j=0; j<len(p); j=j+1) j]) {/* do what you want with p[i] */ } > > for(i=[for(j=0; j<len(p)-1; j=j+1) j]) {/* do what you want with p[i] and > p[i+1] */ } > > These forms of for() work just in list comprehension expressions. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
RP
Ronaldo Persiano
Thu, Mar 9, 2017 3:50 PM

You are right. I think it works if the j definition in the for() is changed
to:

j = [0:1:k<n? 999 : len(p)%1000-1 ] ,

2017-03-09 12:38 GMT-03:00 nop head nop.head@gmail.com:

That goes wrong when len(p) is a multiple of 1000 because for doesn't like
an end that is less that the start.

You are right. I think it works if the j definition in the for() is changed to: j = [0:1:k<n? 999 : len(p)%1000-1 ] , 2017-03-09 12:38 GMT-03:00 nop head <nop.head@gmail.com>: > That goes wrong when len(p) is a multiple of 1000 because for doesn't like > an end that is less that the start. >
NH
nop head
Thu, Mar 9, 2017 3:59 PM

Oh, yes. I wasn't aware of that oddity in for, thanks. I can simplify some
more of my code.

On 9 March 2017 at 15:50, Ronaldo Persiano rcmpersiano@gmail.com wrote:

You are right. I think it works if the j definition in the for() is
changed to:

j = [0:1:k<n? 999 : len(p)%1000-1 ] ,

2017-03-09 12:38 GMT-03:00 nop head nop.head@gmail.com:

That goes wrong when len(p) is a multiple of 1000 because for doesn't
like an end that is less that the start.

Oh, yes. I wasn't aware of that oddity in for, thanks. I can simplify some more of my code. On 9 March 2017 at 15:50, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > You are right. I think it works if the j definition in the for() is > changed to: > > j = [0:1:k<n? 999 : len(p)%1000-1 ] , > > 2017-03-09 12:38 GMT-03:00 nop head <nop.head@gmail.com>: > >> That goes wrong when len(p) is a multiple of 1000 because for doesn't >> like an end that is less that the start. >> > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
RP
Ronaldo Persiano
Thu, Mar 9, 2017 4:54 PM

To make it more readable you may define a function.

function range_of(ini,end) = [for(i=ini; i<end; i=i+1) i];

for(i=range_of(0,len(p)-1)) {}

To make it more readable you may define a function. function range_of(ini,end) = [for(i=ini; i<end; i=i+1) i]; for(i=range_of(0,len(p)-1)) {}
RP
Ronaldo Persiano
Thu, Mar 9, 2017 5:13 PM

If you prefer to use the current OpenSCAD version, you may likewise define
a function to encapsulate the range computation.

function range_of(ini, end) =
let( n = floor((end-ini+1)/1000))
[ for( k = [0:n],
j = [0:1:k<n? 999 : (end-ini+1)%1000-1 ] ,
i = ini+k*1000 + j ) i];

r = range_of(5,100000);
echo(len=len(r),r[0],r[len(r)-1] ); // check

for(i=r) if(i>r[0] && r[i-r[0]]!=r[i-1-r[0]]+1) echo(r[i]); // another check

2017-03-09 13:54 GMT-03:00 Ronaldo Persiano rcmpersiano@gmail.com:

To make it more readable you may define a function.

function range_of(ini,end) = [for(i=ini; i<end; i=i+1) i];

for(i=range_of(0,len(p)-1)) {}

If you prefer to use the current OpenSCAD version, you may likewise define a function to encapsulate the range computation. function range_of(ini, end) = let( n = floor((end-ini+1)/1000)) [ for( k = [0:n], j = [0:1:k<n? 999 : (end-ini+1)%1000-1 ] , i = ini+k*1000 + j ) i]; r = range_of(5,100000); echo(len=len(r),r[0],r[len(r)-1] ); // check for(i=r) if(i>r[0] && r[i-r[0]]!=r[i-1-r[0]]+1) echo(r[i]); // another check 2017-03-09 13:54 GMT-03:00 Ronaldo Persiano <rcmpersiano@gmail.com>: > To make it more readable you may define a function. > > function range_of(ini,end) = [for(i=ini; i<end; i=i+1) i]; > > for(i=range_of(0,len(p)-1)) {} >
DC
David Coneff
Fri, Mar 10, 2017 2:00 AM

Ronaldo & nophead,

Thanks for the help. Those look like good work-arounds for the current
version of OpenSCAD. I will probably have the 10,000 element range problem
bite me later on, for the moment it doesn't pose a serious limitation and
now I'll have a way to solve it if it really becomes necessary. The couple
of libraries that I wanted to get working are basically done, I'll have to
refactor to make sure that the 10,000 element problem doesn't crop up in
them but that will be a project for another day. I'm finding that some of
the computations I want to do to create point sets for polyhedron meshes
aren't really possible unless I move to something like SolidPython or just
plain old python scripts that do the business-logic computations and
generate OpenSCAD code that manipulate pre-calculated lists of points.
Generating big lists to begin with seems to be the general issue, if you
already have them made by something else, list comprehension syntax does a
good job of not limiting how many points you can work with at once.

On Thu, Mar 9, 2017 at 10:13 AM, Ronaldo Persiano rcmpersiano@gmail.com
wrote:

If you prefer to use the current OpenSCAD version, you may likewise define
a function to encapsulate the range computation.

function range_of(ini, end) =
let( n = floor((end-ini+1)/1000))
[ for( k = [0:n],
j = [0:1:k<n? 999 : (end-ini+1)%1000-1 ] ,
i = ini+k*1000 + j ) i];

r = range_of(5,100000);
echo(len=len(r),r[0],r[len(r)-1] ); // check

for(i=r) if(i>r[0] && r[i-r[0]]!=r[i-1-r[0]]+1) echo(r[i]); // another
check

2017-03-09 13:54 GMT-03:00 Ronaldo Persiano rcmpersiano@gmail.com:

To make it more readable you may define a function.

function range_of(ini,end) = [for(i=ini; i<end; i=i+1) i];

for(i=range_of(0,len(p)-1)) {}

Ronaldo & nophead, Thanks for the help. Those look like good work-arounds for the current version of OpenSCAD. I will probably have the 10,000 element range problem bite me later on, for the moment it doesn't pose a serious limitation and now I'll have a way to solve it if it really becomes necessary. The couple of libraries that I wanted to get working are basically done, I'll have to refactor to make sure that the 10,000 element problem doesn't crop up in them but that will be a project for another day. I'm finding that some of the computations I want to do to create point sets for polyhedron meshes aren't really possible unless I move to something like SolidPython or just plain old python scripts that do the business-logic computations and generate OpenSCAD code that manipulate pre-calculated lists of points. Generating big lists to begin with seems to be the general issue, if you already have them made by something else, list comprehension syntax does a good job of not limiting how many points you can work with at once. On Thu, Mar 9, 2017 at 10:13 AM, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > If you prefer to use the current OpenSCAD version, you may likewise define > a function to encapsulate the range computation. > > function range_of(ini, end) = > let( n = floor((end-ini+1)/1000)) > [ for( k = [0:n], > j = [0:1:k<n? 999 : (end-ini+1)%1000-1 ] , > i = ini+k*1000 + j ) i]; > > r = range_of(5,100000); > echo(len=len(r),r[0],r[len(r)-1] ); // check > > for(i=r) if(i>r[0] && r[i-r[0]]!=r[i-1-r[0]]+1) echo(r[i]); // another > check > > > 2017-03-09 13:54 GMT-03:00 Ronaldo Persiano <rcmpersiano@gmail.com>: > >> To make it more readable you may define a function. >> >> function range_of(ini,end) = [for(i=ini; i<end; i=i+1) i]; >> >> for(i=range_of(0,len(p)-1)) {} >> > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >