Randomize order of an array?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Randomize order of an array?

Mike Myerburg
Hi-

I use a modified version of the BatchProcessFolders Macro to analyze all
the images in a folder.  In order to be as objective as possible, I
would like to randomize the order that the images are processed (I have
already blanked out the filename, so I cant cheat that way).  Here is a
snippet of the macro that call sends each file to processFile-

  function processFiles(dir) {
       list = getFileList(dir);
       for (i=0; i<list.length; i++) {
           if (endsWith(list[i], "/"))
               processFiles(""+dir+list[i]);
           else {
              showProgress(n++, count);
              path = dir+list[i];
              processFile(path);
           }
       }
   }

The array list then would contain the ordered list of files.  Is there a
way to randomize the order of these file in the array using the macro
language?

Thanks for the help, Mike
Reply | Threaded
Open this post in threaded view
|

Re: Randomize order of an array?

ctrueden
Hi Mike,

One popular way is the Fisher Yates shuffle:
http://en.wikipedia.org/wiki/Fisher-Yates_shuffle

Here's a Friday afternoon macro for you!

Cheers,
Curtis

//---------------------------
function shuffle(array) {
  n = array.length;       // The number of items left to shuffle (loop
invariant).
  while (n > 1) {
    k = randomInt(n);     // 0 <= k < n.
    n--;                  // n is now the last pertinent index;
    temp = array[n];      // swap array[n] with array[k] (does nothing if k
== n).
    array[n] = array[k];
    array[k] = temp;
  }
}

// returns a random number, 0 <= k < n
function randomInt(n) {
  return n * random();
}

// a little test -- randomize a list of prime numbers
primes = newArray(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
53, 59, 61, 67, 71, 73, 79, 83, 89, 97);
shuffle(primes);
for (i=0; i<primes.length; i++) print(primes[i]);
//---------------------------

On Fri, Feb 27, 2009 at 3:28 PM, Mike Myerburg <[hidden email]> wrote:

> Hi-
>
> I use a modified version of the BatchProcessFolders Macro to analyze all
> the images in a folder.  In order to be as objective as possible, I would
> like to randomize the order that the images are processed (I have already
> blanked out the filename, so I cant cheat that way).  Here is a snippet of
> the macro that call sends each file to processFile-
>
>  function processFiles(dir) {
>      list = getFileList(dir);
>      for (i=0; i<list.length; i++) {
>          if (endsWith(list[i], "/"))
>              processFiles(""+dir+list[i]);
>          else {
>             showProgress(n++, count);
>             path = dir+list[i];
>             processFile(path);
>          }
>      }
>  }
>
> The array list then would contain the ordered list of files.  Is there a
> way to randomize the order of these file in the array using the macro
> language?
>
> Thanks for the help, Mike
>
Reply | Threaded
Open this post in threaded view
|

Re: Randomize order of an array?

dscho
In reply to this post by Mike Myerburg
Hi,

On Fri, 27 Feb 2009, Mike Myerburg wrote:

> I use a modified version of the BatchProcessFolders Macro to analyze all
> the images in a folder.  In order to be as objective as possible, I
> would like to randomize the order that the images are processed (I have
> already blanked out the filename, so I cant cheat that way).  Here is a
> snippet of the macro that call sends each file to processFile-
>
>  function processFiles(dir) {
>       list = getFileList(dir);
>       for (i=0; i<list.length; i++) {
>           if (endsWith(list[i], "/"))
>               processFiles(""+dir+list[i]);
>           else {
>              showProgress(n++, count);
>              path = dir+list[i];
>              processFile(path);
>           }
>       }
>   }
>
> The array list then would contain the ordered list of files.  Is there a
> way to randomize the order of these file in the array using the macro
> language?

Maybe you want something like this (totally untested):

function randomize(array) {
        for (i = 0; i < array.length - 1; i++) {
                j = i + floor(random() * (array.length - i));
                if (i != j) {
                        swap = array[j];
                        array[j] = array[i];
                        array[i] = swap;
                }
        }
}

The idea is to iterate over all indices (except the last one), pick a
random index greater or equal to that index, and swap the respective list
items.  (You might need to fix the code to implement that idea; as I said,
I did not test.)

You would call the function directly after calling getFileList():

        list = randomize(list);

However, I see that you may have subdirectories; you will have to build a
complete list of all files before randomizing in order to get an unbiased
result.

Ciao,
Dscho
Reply | Threaded
Open this post in threaded view
|

Re: Randomize order of an array?

dscho
In reply to this post by ctrueden
Hi,

On Fri, 27 Feb 2009, Curtis Rueden wrote:

> //---------------------------
> function shuffle(array) {
>   n = array.length;       // The number of items left to shuffle (loop
> invariant).
>   while (n > 1) {
>     k = randomInt(n);     // 0 <= k < n.
>     n--;                  // n is now the last pertinent index;

Did you not mean to decrement n later in the loop?

>     temp = array[n];      // swap array[n] with array[k] (does nothing if k
> == n).
>     array[n] = array[k];
>     array[k] = temp;

Like here?

Ciao,
Dscho
Reply | Threaded
Open this post in threaded view
|

Re: Randomize order of an array?

ctrueden
Hi Johannes,

Did you not mean to decrement n later in the loop?
>

Well, I did steal it straight from the Wikipedia page, but I tested and it
works as written.

Intuitively, the n-- in in the right place because ImageJ macro arrays are
0-indexed, n starts at array.length, and the loop ends when n == 1.

-Curtis

On Fri, Feb 27, 2009 at 4:15 PM, Johannes Schindelin <
[hidden email]> wrote:

> Hi,
>
> On Fri, 27 Feb 2009, Curtis Rueden wrote:
>
> > //---------------------------
> > function shuffle(array) {
> >   n = array.length;       // The number of items left to shuffle (loop
> > invariant).
> >   while (n > 1) {
> >     k = randomInt(n);     // 0 <= k < n.
> >     n--;                  // n is now the last pertinent index;
>
> Did you not mean to decrement n later in the loop?
>
> >     temp = array[n];      // swap array[n] with array[k] (does nothing if
> k
> > == n).
> >     array[n] = array[k];
> >     array[k] = temp;
>
> Like here?
>
> Ciao,
> Dscho
>
Reply | Threaded
Open this post in threaded view
|

Re: Randomize order of an array?

Mike Myerburg
In reply to this post by ctrueden
Awesome!

Worked perfectly.  Thanks

Curtis Rueden wrote:

> Hi Mike,
>
> One popular way is the Fisher Yates shuffle:
> http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
>
> Here's a Friday afternoon macro for you!
>
> Cheers,
> Curtis
>
> //---------------------------
> function shuffle(array) {
>   n = array.length;       // The number of items left to shuffle (loop
> invariant).
>   while (n > 1) {
>     k = randomInt(n);     // 0 <= k < n.
>     n--;                  // n is now the last pertinent index;
>     temp = array[n];      // swap array[n] with array[k] (does nothing if k
> == n).
>     array[n] = array[k];
>     array[k] = temp;
>   }
> }
>
> // returns a random number, 0 <= k < n
> function randomInt(n) {
>   return n * random();
> }
>
> // a little test -- randomize a list of prime numbers
> primes = newArray(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
> 53, 59, 61, 67, 71, 73, 79, 83, 89, 97);
> shuffle(primes);
> for (i=0; i<primes.length; i++) print(primes[i]);
> //---------------------------
>
> On Fri, Feb 27, 2009 at 3:28 PM, Mike Myerburg <[hidden email]> wrote:
>
>> Hi-
>>
>> I use a modified version of the BatchProcessFolders Macro to analyze all
>> the images in a folder.  In order to be as objective as possible, I would
>> like to randomize the order that the images are processed (I have already
>> blanked out the filename, so I cant cheat that way).  Here is a snippet of
>> the macro that call sends each file to processFile-
>>
>>  function processFiles(dir) {
>>      list = getFileList(dir);
>>      for (i=0; i<list.length; i++) {
>>          if (endsWith(list[i], "/"))
>>              processFiles(""+dir+list[i]);
>>          else {
>>             showProgress(n++, count);
>>             path = dir+list[i];
>>             processFile(path);
>>          }
>>      }
>>  }
>>
>> The array list then would contain the ordered list of files.  Is there a
>> way to randomize the order of these file in the array using the macro
>> language?
>>
>> Thanks for the help, Mike
>>
>