We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › a function that passes multiple values
Page Index Toggle Pages: 1
a function that passes multiple values? (Read 1793 times)
a function that passes multiple values?
Oct 1st, 2009, 8:05am
 
I'd like to use a function that creates an ordered array and then pass the values to draw frame by frame, but so far it seems a function will only pass one value at a time? Since the function reorders the array every time it's called, I lose the order. What I'm trying to do is to create an 'urn' function - i.e. random selection without replacement:

void setup() {
 size(400, 400);
 frameRate(10);
 noLoop();
}

void draw() {
 int x = urn(5);
 print(x+" ");
}

int urn (int num) {
 int [] balls = new  int[num]; // initialize the array
 int choice = 0;
 int index = 0;
 for (int i = 0; i < num; i++)
 {
   balls[i] = i; // fill the array with a sequence of integers starting with 0
 }
 for (int j = num; j > 0; j--) {
   index = int(random(0, j)); // choose a # between 0 and num
   choice = (balls[index]); //use it as an index to choose a value from the array
   balls[index] = balls[j-1]; // move the last element in the array
//    print(choice + " "); // to the place where the choice came from
 }
 return balls;
}
Re: a function that passes multiple values?
Reply #1 - Oct 1st, 2009, 9:30am
 
Make balls global and call urn from setup?
Re: a function that passes multiple values?
Reply #2 - Oct 1st, 2009, 11:03am
 
I've actually found a solution that works something like that, PhiLho. I've made a function that works on a global array and is called from draw every nth frame, where n is the size of the array. It is possible, i've found, to return an array with a function, but the point is that i don't want the whole array every iteration. I'd still ideally like to create a function that takes the array size and a pointer to its contents as parameters and then  releases the reordered items one at a time until its empty, but perhaps this is not possible (?).
Re: a function that passes multiple values?
Reply #3 - Oct 1st, 2009, 11:31am
 
Quote:
i don't want the whole array every iteration
It isn't really important, it is only a reference that is returned, so it is lightweight.

Quote:
but perhaps this is not possible
(nearly) Everything is possible... And your wish isn't too hard to implement.
Code:
int urn() {
if (num == BALL_NB) {
balls = new int[BALL_NB]; // initialize or clear the array
num = 0;
int choice = 0;
int index = 0;
for (int i = 0; i < BALL_NB; i++)
{
balls[i] = i;
}
for (int j = BALL_NB; j > 0; j--) {
index = int(random(0, j));
choice = balls[index];
balls[index] = balls[j-1];
}
}
return balls[num++];
}
(untested)
Re: a function that passes multiple values?
Reply #4 - Oct 1st, 2009, 2:01pm
 
PhiLho, that code doesn't work, partly because of mistakes I'd missed, but also I think because the needed array is local. But I hadn't realized that the index value of an array could be incremented in the way you've shown, so that's helpful. I'll work on it.
Re: a function that passes multiple values?
Reply #5 - Oct 1st, 2009, 6:40pm
 
From what I understand of your original problem statement, here's a suggestion.

You could keep a counter that is updated every time draw() has been called. That will keep track of how many array elements you have consumed. Suppose you have function fillArray() that creates an ordered list of values in a global array x[], and returns the number of array elements (which may vary with each call). How about something like:

int numArrLeft = 0; // number of elements left in array
int currIndex = 0;
int [] x;

void setup() {
 // some stuff
}

void draw() {
 if (numArrLeft == 0) {
   numArrLeft = fillArr();
 }
 numArrLeft--;
 // use next array element x[currIndex]
 currIndex++;
}

This assumes that you continuously pump out array elements, and consume them one per frame.

If you only create a new array every once in a while, you would replace if (numArrLeft == 0) with some other trigger condition for making new array elements.

Hope this is somewhat close to what you need...

Bill


Re: a function that passes multiple values?
Reply #6 - Oct 1st, 2009, 6:43pm
 
Ack, my C/C++ habits are creeping up on me. In my suggestion code, obviously if you resize the array x[] properly every time, you can just check x.length and not make the function return the array size.

Bill
Re: a function that passes multiple values?
Reply #7 - Oct 2nd, 2009, 1:32am
 
sonic wrote on Oct 1st, 2009, 2:01pm:
PhiLho, that code doesn't work, partly because of mistakes I'd missed, but also I think because the needed array is local
It isn't in my code: I don't declare the array in the function, I left you to declare it at global level... Same for num.
Re: a function that passes multiple values?
Reply #8 - Oct 2nd, 2009, 3:05am
 
Then, PhiLho, I guess I missed the point of you making an adjustment to my code and re-posting it. Bill, thanks for the suggestion - I"m not sure you caught the part about the array needing to be randomly reordered every time it's renewed (?). This is random selection without replacement.

In any case, here is the code I'm using at present that works. That it works is great, but what I dislike is that it isn't more self-contained as a function - ideally I'd like to simply specify the number of members of the array as a parameter of the function and let the function do the rest. Perhaps what I need to do is create an object? i really don't understand objects yet, so I guess I'll see when I get there.

void setup() {
 size(400, 400);
 frameRate(10);
}

int choice = 0;
int index = 0;
int num = 7;
int [] order = new int[num];
int k = num;

void draw() {
 if (k == num) {
   urn();
    k = k - 1;
 }
 else if ((k < num) && (k > 1)) {
    k = k - 1;
 }
   else if (k == 1) {
    k = num;
}
}

void urn() {
 int [] balls = new  int[num]; // initialize the array

 for (int i = 0; i < num; i++)
 {
   balls[i] = i; // fill the array with a sequence of integers starting with 0
 }
 for (int j = num-1; j > -1; j--) {
   index = int(random(0, j)); // choose a # between 0 and num
   choice = (balls[index]); //use it as an index to choose a value from the array
   order[j] = choice; // put the choice into the ordered array
   balls[index] = balls[j]; // move the last element in the urn to the place where the choice came from
 }

}
Re: a function that passes multiple values?
Reply #9 - Oct 2nd, 2009, 3:54am
 
OK, I think you don't get the point of my code.
Take my urn() function and add it after that code:
Code:
int[] balls;
final int BALL_NB = 10;
int num = BALL_NB;

void setup() {
size(400, 400);
frameRate(10);
}

void draw() {
int x = urn();
print(x + " ");
}

If I understood correctly your need, it should do what you want.

Quote:
what I dislike is that it isn't more self-contained as a function

Indeed, but in Java, a function cannot retain persistent data between calls, unlike C/C++ (with static variables).
You guessed right about making a class: that's the way to have persistent data along with methods to work on it.
You don't know that, but so called global variables in Processing are actually fields of a hidden class: you are already using a class!
But let's do one explicitly. That isn't hard, really.
Code:
final int BALL_NB = 20;
URN urn = new URN(BALL_NB);

void setup() {
 size(400, 400);
 frameRate(10);
}

void draw() {
 int x = urn.get();
 print(x + " ");
 if (urn.isExhausted())
 {
   println(""); // New line
 }
}

class URN
{
 private int[] balls;
 private int ballNb = 10; // Default value
 private int num; // Set at 0 by default
 static final int LARGE_PRIME = 444443;

 // The constructor: same name as class, no return type
 public URN(int bn)
 {
   ballNb = bn;
   generateArray();
 }
 
 public int get()
 {
   if (num == ballNb)
   {
num = 0;
generateArray();
   }
   return balls[num++];
 }
 
 public boolean isExhausted()
 {
   return num == ballNb;
 }
 
 public int getNum()
 {
   return num;
 }
 
 // Private: only the class can use it
 private void generateArray()
 {
   balls = new int[ballNb]; // initialize or clear the array
   int index = int(random(0, ballNb));
   for (int i = 0; i < ballNb; i++)
   {
index = (index + LARGE_PRIME) % ballNb;
balls[index] = i;
   }
 }
}

Your shuffle algorithm wasn't working (unfinished?), so I replaced it with a well known one.
Not perfect: with a same starting point, you get the same sequence. Can be spiced up by taking also a random large prime number...
Re: a function that passes multiple values?
Reply #10 - Oct 2nd, 2009, 4:57am
 
My old shuffle algorithm wasn't working, but the new one seems to be. It clearly returns a newly ordered array (named 'order') each nth draw (where n is the array size) without repeating any members of the array when they're retrieved. It will be a while before I can have a look at your code, but one thing you could explain is your use of uppercase - what does it indicate?

thanks
Re: a function that passes multiple values?
Reply #11 - Oct 2nd, 2009, 6:46am
 
All uppercase identifiers (with parts separated by underscores) traditionally denote constants, variables whose value should not/must not change over time.
In Java, this is enforced by the final keyword: if you try to change such value, the compiler will protest...
Re: a function that passes multiple values?
Reply #12 - Oct 2nd, 2009, 7:35am
 
Actually, I used an interesting algorithm allowing to visit in a semi-random way all indexes of an array (all cells of a table, etc.).
It works well, but has drawbacks in your usage. You can also use the Fisher–Yates shuffle:
Code:
  private void generateArray()
 {
   balls = new int[ballNb]; // initialize or clear the array
   for (int i = ballNb - 1; i >= 0; i--)
   {
balls[i] = i;
   }
   for (int i = ballNb - 1; i >= 0; i--)
   {
int index = int(random(0, i + 1));
int p = balls[index];
balls[index] = balls[i];
balls[i] = p;
   }
 }
Ah, looking again, it is your original algorithm, just with the missing part...  Grin
Page Index Toggle Pages: 1