Jump to content
MadMax50

learning foreach loop in vex

Recommended Posts

Hello,

I am trying to understand the foreach loop in vex. I want to loop over my boxes and assign a random color to it. 

So if the structure of the foreach loop is like this:

foreach( element; array) {
     // do things to element
 }

So if I were to apply this to my example of randomizing color on boxes:

the "array" should be the class attribute stored in a custom array... and the "element" should be the iteration of each class right ?

I'm stuck on storing the class attribute into an array. I know how to make a custom array like this:

float myclass[]={1,2,22,3,45};

but how would I store an attribute into an array?

If anyone can give me a simple example of how this works. It would be much appreciated.

Thank you.

Share this post


Link to post
Share on other sites
Posted (edited)

Attribute Array declaration is slightly different than standard array.

f[]@myclass = {1,2,22,3,45};
float val = f[]@myclass[3];

Apparently this syntax disturbs more than one (me the first). I Already respond to this question three days ago :rolleyes:.
It must be said that this particular sintax is not really easy to find in the doc.
It's in the array section of the Using VEX expressions chapter, but not in the declare attibutes section and not in the array chapter !

Check the Mestela Wiki for more infos
http://www.tokeru.com/cgwiki/?title=HoudiniVex#Arrays

Edited by flcc

Share this post


Link to post
Share on other sites

@flccThank you for the response. I understand how to create array attributes manually. My issue is that I don't no how to get an existing attribute like @class created by the connectivity sop and store those values in an array. 

All the documentation I read up on does not explain this even on Mestelas Wiki or Joy of VEX. 

Perhaps I am thinking about arrays differently than they are supposed to be used? Would love to get any insight.

Thanks again.

 

Share this post


Link to post
Share on other sites

To accumulate an array of all your class attributes it is my understanding that you would have to loop over every prim, check to see if that prim's class is already in your array and if it isn't then append it.

Then if you wanted to loop over each object like you said you could use

for (int i:array)

which is something vex picked up from c++

then you would have to loop over each prim again to see if it has a matching class attrib and only then could you assign a random value

 

instead you could loop over each primitive in a detail and assign it a random colour based on the class attribute.

for (int primitive=0;prim<nprimitives(0);prim++)

{

       vector randCd=rand(prim(0,"class",primitive));

       setprimattrib(0,"Cd",primitive,randCd,"set");

}

 

 

Share this post


Link to post
Share on other sites
15 hours ago, MadMax50 said:

how to get an existing attribute like @class created by the connectivity sop and store those values in an array

This, in a detail wrangle, will do it; although as you'll see it's quite a roundabout way to work:

// Construct `class` array from the prim attribute.
int class[], primclass;
for(int primnum = 0; primnum < nprimitives(0); primnum++) {
    primclass = prim(0, 'class', primnum);
    push(class, primclass);
}

// Construct `class_uniques` array from `class` without duplicates.
int class_uniques[], count = 0;
if (len(class)) {  // Proceed only if the array is non-empty.
    class = sort(class);
    
    // Add the first element, so we have something to compare against below.
    push(class_uniques, class[0]);
    count++;
    
    foreach(int elem; class[1:]) {  // For each, leaving the first element out.
        // If the current element is different from the preceding one, add it.
        if (elem != class_uniques[count-1]) {
            push(class_uniques, elem);
            count++;
        }
    }
}

i[]@class_uniques = class_uniques;

Instead of doing this, I would suggest using a For-Each SOP block. It's much simpler, and I assume also more efficient. If you want to have a look, the attached file shows both approaches for setting color by connectivity class.

class_to_array__forum.hiplc

Share this post


Link to post
Share on other sites

@flcc @pabcou @ColecloughGeorge @ikoon

Thank you everyone for the help. I will definitely be reading through those links you sent me. 

@ColecloughGeorgeThank you for the file. I didn't realize that doing something so simple would be that complicated with a foreach in vex.

My follow up question with your code would have to be this:

1. What is the difference between a "for" and a "foreach". Aren't both doing pretty much the same thing ?

Share this post


Link to post
Share on other sites

A for loop requires you to control the variable you're iterating, do your own comparison, and extract the element of an array yourself.

A foreach does all that for you.

These are functionally equivalent:

int myarray[] = {2345,3456,234,34,6,8,567,34,5,346,45};


for (int i = 0; i < len(myarray); i++) {
   @P.x += myarray[i];
}


// vs...

foreach(int element; myarray) {
   @P.x += element; 
}

 

  • Like 1

Share this post


Link to post
Share on other sites

You supply for loops with a variable to iterate over, a condition that if not true will stop the loop and something that happens to the variable each loop. For example you could have:

for (int i=5; i>1; i/2)

You can also have for loops that iterate over array members such as

for (int i:array)

foreach (int i;array)

Functionally these both do the same thing to my knowledge.

 

Also I believe the above answer is wrong as those two for loops will have different results. E.g.

int array[]={5,9,2,8};

foreach(int i; array)

      printf i;

//This would return 5,9,2,8

for (int i=0; i<len(array); i++)

      printf i;

//This would return 0,1,2,3

There is a great website for some nice syntax hints

http://www.cplusplus.com/doc/tutorial/control/

Share this post


Link to post
Share on other sites

The above answer is wrong? My one? Look closer; the first example uses the iterator 'i' to get a value from the array, the other one accesses the array value directly.

 

 

Share this post


Link to post
Share on other sites
16 hours ago, pabcou said:

Instead of doing this, I would suggest using a For-Each SOP block

you can easily remove your For Each Loop, Prim Wrangle with @Cd = rand(i@class); is enough to randomize color per class

Share this post


Link to post
Share on other sites

@mestela Thank you for the reply. That makes sense to me now. 
I guess the reason for my original question of this thread was to get as many examples as I can to understand for loops in vex. I went through the examples on Joy of Vex talking about loops in relation to the nearpoints function but I think I need to see even more examples of how they work. That is why I thought my randomize color based of @class idea was going to be a fairly basic example but apparently not haha. 

I already started a master file for all the for loop examples I came across so far.

Thank you .

Share this post


Link to post
Share on other sites
On 29/06/2019 at 10:27 AM, mestela said:

The above answer is wrong? My one? Look closer; the first example uses the iterator 'i' to get a value from the array, the other one accesses the array value directly.

 

 

Apologies

Share this post


Link to post
Share on other sites
On 6/29/2019 at 12:09 PM, anim said:

you can easily remove your For Each Loop

Thank you for pointing this out, Tomas.

On 6/28/2019 at 8:33 PM, MadMax50 said:

I didn't realize that doing something so simple would be that complicated with a foreach in vex.

It turns out it can be simplified. I've just learned about the `uniquevals` function, which, per the docs, "returns the set of unique values across all values for an int or string attribute." So it seems like a direct answer to your original question. Using it, you can get rid of all the code in my previous post, and instead put this in a Detail Wrangle:

int class[] = uniquevals(0, 'prim', 'class');

foreach(int elem; class) {
    vector Cd = rand(elem);
    int prims[] = findattribval(0, 'prim', 'class', elem);
    foreach(int prim; prims) {
        setprimattrib(0, 'Cd', prim, Cd);
    }
}

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×