Array processing function

I’m attempting to create a function to do basic array manipulation. I’d like to pass it an empty array and have the new array returned. I’ve included the code below, but I am not sure how to get it to work correctly.

I was also hoping to get randomly-timed intervals, by resetting the frameCount % value. This function does not seem to be operating correctly either, if anyone has any ideas.

Thanks for the help!

void setup(){
size(640, 480);
background(100, 10, 100);
}

void coord(float [] arr1){
  for (int x = 0; x < 20; x++) {
    arr1[x] = random(1);
  };
};

void draw() { 
  float [] locArr = new float[20];
  int amt=100;
  if ((frameCount%amt) == 1) 
  {
    coord(locArr);
      amt = int(random(100)); 
  };
  println(locArr);
};

If you’re gonna return a new array, why would you need to pass an empty array?

You could simply return a new array regardless.

Besides, you’re actually passing an array w/ length 20 to your function coord():
float [] locArr = new float[20];
coord(locArr);

And inside coord() you fill up the array w/ a range value 0 to 1.

The function is working as you want. The problem is that you are re-creating the array as empty each time draw() gets called, so you’re wiping out the values coord() gave you. Move your println() to inside the if() block.

Keep in mind that the default frameCount goes up 60 times per second. You’re spewing out println()s that often.

1 Like

OK - I might be a little confused here. Let me see if I can break it down.

My goal is to produce a dozen or so different arrays using a “coord” function.
My understanding is that coord does not “return” anything… i.e., if I have something like the following, nested in my draw() function:

locArray = coord();

It will produce a “cannot convert from void to float[]” error.
So, I’m assuming I need to pass some sort of variable into the coord argument, load it with array values, and then use the variable in the rest of the code body.

The issue then, as @scudly poitns out - is that draw() wipes out the array on each frame. This becomes a problem if I need to have access to the arrays outside of this particular if Block.

Maybe I’m still a little hazy on the scope and function aspects of Processing/Java. Apparently, you can’t even pass the variable into an else statement, as the following produces an “locArr cannot be resolved to a variable” error.

void setup(){
size(640, 480);
background(100, 10, 100);
}

void coord(float [] arr1){
  for (int x = 0; x < 20; x++) {
    arr1[x] = random(1);
  };
};

void draw() { 
  int amt=100;
  if ((frameCount%amt) == 1) 

  {
  float [] locArr = new float[20];
  coord(locArr);
  amt = int(random(100));
        
  }
  else {println(locArr);}
};

My next thought was to wrap it in a for loop. This didn’t work either…

void setup(){
size(640, 480);
background(100, 10, 100);
}

void coord(float [] arr1){
  for (int x = 0; x < 20; x++) {
    arr1[x] = random(1);
  };
};

void draw() { 
  int amt=100;
 
 for (int n = 0; n < 1; n++) {
     float [] locArr = new float[20];
  
  if ((frameCount%amt) == 1) 
  {
  coord(locArr);
  amt = int(random(100));
        
  }
  else {println(locArr);}
 };
};

Yes, you have some scoping problems. For one thing, amt is getting reset to 100 at the start of every draw().

Try this code to see if it’s closer to what you want:

float [] arr;
int amt = 100;

void setup() {
  size( 640, 480 );
  arr = new float[20];
}

void coord( float [] arr1 ) {
  for( int i=0; i<20; i++ ) {
    arr1[i] = random( width );
  }
}

void draw() {
  background( 0 );

  if( (frameCount % amt) == 0 ) {
    coord( arr );
    amt = int(random(100));
  }
    
  for( int i=0; i<20; i++ )
    circle( arr[i], height/2, 20 );
}

That definitely simplifies things - thank you!

The only question I have remaining is if you wanted to do something like the following, where you wrap a bunch of iterations, in a For Loop, so that you could pull several different random arrays from the same function… my hope was that “arr” would be rewritten for each instance, but now I’m wondering if I need to juggle with something in the void setup().

   for ( int  n = 0; n < 3; n++) {
    for( int i=0; i<20; i++ )
      circle( arr[i], height/2, 20 );
    }
  }

[EDITED]

my version from scudly


float[] arr;
int amt = 40;

void setup() {
  size( 640, 480 );
  arr = coord();
}

void draw() {
  background(0);

  if (frameCount % amt == 0) {
    arr = coord();
    amt = int(random(1, 100));
  }

  for ( int i=0; i<20; i++ )
    ellipse(arr[i], height/2, 20, 20);
}

// ------------------------------------------------

float[] coord() {

  float[] arrResult = new float[20];

  for (int i=0; i<20; i++) {
    arrResult[i] = random(width);
  }

  return arrResult;
}

Your question about for-loops

not sure if I understand you here.

remember that the screen is not updated throughout (not inside the for-loops) but only at the end of draw(). Therefore, your nested for loop would not show what you expect.
Instead the approach by scudly is correct: it uses the fact that draw() loops automatically and that it updates the screen at its end. The array gets updated coord( arr ); (“pull several different random arrays from the same function”).
Essentially scudly’s solution is equivalent to your nested for loop, except that the outer for loop is replaced by draw() itself, which loops automatically.

Chrisir

A change Chrisir made but didn’t mention (and that I realized after going to bed last night) is that int(random(100)) returns values from 0 up to 99 which might occasionally give a value of 0 and you can’t compute mod 0. So it’s better to limit the range to random(1, 100).

Even better, there is no reason to use % at all. Just count down each frame and leave frameCount out of it.

if( --amt == 0 ) {
  arr = coord();
  amt = int(random(1, 100));
}

But that’s all a side issue to your variable scoping.

Any variable that you declare inside of draw() will get re-declared every frame. If you want anything to persist for more than 1/60 of a second, you have to scope the variable globally. You can call coord() repeatedly and get different sets of randomized arrays, but if you want the results to last, you have to use multiple arrays that are all stored at the global scope – either different variables or an array of arrays.

You can also think of an array of arrays as just one big 1-dimensional array. Fill an array with 60 numbers and just use 20 at a time.

arr = new float[60];  // at the global scope

for( int n=0; n<3; n++ )
  for( int i=0; i<20; i++ )
    circle( arr[ n*20+i ], height*(n+0.5)/3, 20 );
1 Like

The main problem with this code is that it assumes that

  1. the parameter arr1 is not null in other words the array exists and
  2. if the array exists it contains at least 20 elements

It would be best if we create a function that avoids both these issues like this

float[] coord(float [] target) {
  if (target == null) { 
    // create the array if it doesn't exit
    target = new float[20];
  }
  for (int x = 0; x < target.length; x++) { 
    // for each element in the array assign a random number between 0 and 1
    target[x] = random(1);
  }
  return target;
}

If the array does not exist i.e. target == null then it creates a new array otherwise it uses the existing array.

Notice the for loop uses target.length to find the number of elements in an array. This is a safe way to do it.

The following sketch shows it in action. Press ‘n’ key for a new array or ‘e’ key to use an existing array

float[] a = new float[20];

void setup() {
  size(640, 480);
}

float[] coord(float [] target) {
  if (target == null) {
    target = new float[20];
  }
  for (int x = 0; x < target.length; x++) {
    target[x] = random(1);
  }
  return target;
}

void keyTyped() {
  if (key == 'n') { // replace existing array with new with random data
    a = coord(null);
  }
  if (key == 'e') { // populate existing array with new random data
    a = coord(a);
  }
  println("-------------------------------------");
  println(a);
}

void draw() { 
  background(100, 10, 100);
  fill(0, 255, 0);
  noStroke();
  for (int i = 0; i < a.length; i++) {

    ellipse((i*20)+20, a[i]*height, 16, 16);
  }
}
2 Likes