How to make a nested loop dynamic? - for-loop

I have a problem:
For example, there are N number of generations, and I want to execute these generations in jstree like parents and children.
I can only use a fixed number of nested for loops. I don't know how to make it dynamic, i.e., I want to nest N for loops.
How can I do this?
I can only use a fixed number of nested loops, such as
for (i=0;i<=list1.size;i++){
for (j=0;j<=list2.size;j++){
// and some other loops
}
}
but this is static. I want to be able to dynamically execute N number of loops.

As you said, you can't have an arbitrary number of nested for-loops. The way to achieve this is by using recursion.
Here's an example:
function foo(list_of_lists) {
// base case
if (list_of_lists.length == 0) return;
// otherwise, we'll get the head of the list, and continue
list = list_of_lists[0];
for (var idx = 0; idx <= list.length; idx++) {
// do something
// now recursively nest the next list in a for-loop
foo(list_of_lists.splice(1));
}
}
For N lists, this will build up nested for-loops that look like:
for (var idx = 0; idx <= list0.length; idx++) {
for (var idx2 = 0; idx2 <= list2.length; idx2++) {
for (var idx3 = 0; idx3 <= list3.length; idx3++) {
...
}
}
}

If you need a jstree specific solution - set core.data to a function - it will be executed each time a node needs to be loaded - that way you can have an "infinite" dynamic tree so to speak.

Related

Method reference giving run time error, where as Supplier Interface works [duplicate]

What does ArrayIndexOutOfBoundsException mean and how do I get rid of it?
Here is a code sample that triggers the exception:
String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
System.out.println(names[i]);
}
Your first port of call should be the documentation which explains it reasonably clearly:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
So for example:
int[] array = new int[5];
int boom = array[10]; // Throws the exception
As for how to avoid it... um, don't do that. Be careful with your array indexes.
One problem people sometimes run into is thinking that arrays are 1-indexed, e.g.
int[] array = new int[5];
// ... populate the array here ...
for (int index = 1; index <= array.length; index++)
{
System.out.println(array[index]);
}
That will miss out the first element (index 0) and throw an exception when index is 5. The valid indexes here are 0-4 inclusive. The correct, idiomatic for statement here would be:
for (int index = 0; index < array.length; index++)
(That's assuming you need the index, of course. If you can use the enhanced for loop instead, do so.)
if (index < 0 || index >= array.length) {
// Don't use this index. This is out of bounds (borders, limits, whatever).
} else {
// Yes, you can safely use this index. The index is present in the array.
Object element = array[index];
}
See also:
The Java Tutorials - Language Basics - Arrays
Update: as per your code snippet,
for (int i = 0; i<=name.length; i++) {
The index is inclusive the array's length. This is out of bounds. You need to replace <= by <.
for (int i = 0; i < name.length; i++) {
From this excellent article: ArrayIndexOutOfBoundsException in for loop
To put it briefly:
In the last iteration of
for (int i = 0; i <= name.length; i++) {
i will equal name.length which is an illegal index, since array indices are zero-based.
Your code should read
for (int i = 0; i < name.length; i++)
^
It means that you are trying to access an index of an array which is not valid as it is not in between the bounds.
For example this would initialize a primitive integer array with the upper bound 4.
int intArray[] = new int[5];
Programmers count from zero. So this for example would throw an ArrayIndexOutOfBoundsException as the upper bound is 4 and not 5.
intArray[5];
What causes ArrayIndexOutOfBoundsException?
If you think of a variable as a "box" where you can place a value, then an array is a series of boxes placed next to each other, where the number of boxes is a finite and explicit integer.
Creating an array like this:
final int[] myArray = new int[5]
creates a row of 5 boxes, each holding an int. Each of the boxes has an index, a position in the series of boxes. This index starts at 0 and ends at N-1, where N is the size of the array (the number of boxes).
To retrieve one of the values from this series of boxes, you can refer to it through its index, like this:
myArray[3]
Which will give you the value of the 4th box in the series (since the first box has an index of 0).
An ArrayIndexOutOfBoundsException is caused by trying to retrieve a "box" that does not exist, by passing an index that is higher than the index of the last "box", or negative.
With my running example, these code snippets would produce such an exception:
myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //way to high
How to avoid ArrayIndexOutOfBoundsException
In order to prevent ArrayIndexOutOfBoundsException, there are some key points to consider:
Looping
When looping through an array, always make sure that the index you are retrieving is strictly smaller than the length of the array (the number of boxes). For instance:
for (int i = 0; i < myArray.length; i++) {
Notice the <, never mix a = in there..
You might want to be tempted to do something like this:
for (int i = 1; i <= myArray.length; i++) {
final int someint = myArray[i - 1]
Just don't. Stick to the one above (if you need to use the index) and it will save you a lot of pain.
Where possible, use foreach:
for (int value : myArray) {
This way you won't have to think about indexes at all.
When looping, whatever you do, NEVER change the value of the loop iterator (here: i). The only place this should change value is to keep the loop going. Changing it otherwise is just risking an exception, and is in most cases not necessary.
Retrieval/update
When retrieving an arbitrary element of the array, always check that it is a valid index against the length of the array:
public Integer getArrayElement(final int index) {
if (index < 0 || index >= myArray.length) {
return null; //although I would much prefer an actual exception being thrown when this happens.
}
return myArray[index];
}
To avoid an array index out-of-bounds exception, one should use the enhanced-for statement where and when they can.
The primary motivation (and use case) is when you are iterating and you do not require any complicated iteration steps. You would not be able to use an enhanced-for to move backwards in an array or only iterate on every other element.
You're guaranteed not to run out of elements to iterate over when doing this, and your [corrected] example is easily converted over.
The code below:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i< name.length; i++) {
System.out.print(name[i] + "\n");
}
...is equivalent to this:
String[] name = {"tom", "dick", "harry"};
for(String firstName : name) {
System.out.println(firstName + "\n");
}
In your code you have accessed the elements from index 0 to the length of the string array. name.length gives the number of string objects in your array of string objects i.e. 3, but you can access only up to index 2 name[2],
because the array can be accessed from index 0 to name.length - 1 where you get name.length number of objects.
Even while using a for loop you have started with index zero and you should end with name.length - 1. In an array a[n] you can access form a[0] to a[n-1].
For example:
String[] a={"str1", "str2", "str3" ..., "strn"};
for(int i=0; i<a.length(); i++)
System.out.println(a[i]);
In your case:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
For your given array the length of the array is 3(i.e. name.length = 3). But as it stores element starting from index 0, it has max index 2.
So, instead of 'i**<=name.length' you should write 'i<**name.length' to avoid 'ArrayIndexOutOfBoundsException'.
So much for this simple question, but I just wanted to highlight a new feature in Java which will avoid all confusions around indexing in arrays even for beginners. Java-8 has abstracted the task of iterating for you.
int[] array = new int[5];
//If you need just the items
Arrays.stream(array).forEach(item -> { println(item); });
//If you need the index as well
IntStream.range(0, array.length).forEach(index -> { println(array[index]); })
What's the benefit? Well, one thing is the readability like English. Second, you need not worry about the ArrayIndexOutOfBoundsException
The most common case I've seen for seemingly mysterious ArrayIndexOutOfBoundsExceptions, i.e. apparently not caused by your own array handling code, is the concurrent use of SimpleDateFormat. Particularly in a servlet or controller:
public class MyController {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
public void handleRequest(ServletRequest req, ServletResponse res) {
Date date = dateFormat.parse(req.getParameter("date"));
}
}
If two threads enter the SimplateDateFormat.parse() method together you will likely see an ArrayIndexOutOfBoundsException. Note the synchronization section of the class javadoc for SimpleDateFormat.
Make sure there is no place in your code that are accessing thread unsafe classes like SimpleDateFormat in a concurrent manner like in a servlet or controller. Check all instance variables of your servlets and controllers for likely suspects.
You are getting ArrayIndexOutOfBoundsException due to i<=name.length part. name.length return the length of the string name, which is 3. Hence when you try to access name[3], it's illegal and throws an exception.
Resolved code:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i < name.length; i++) { //use < insteadof <=
System.out.print(name[i] +'\n');
}
It's defined in the Java language specification:
The public final field length, which contains the number of components
of the array. length may be positive or zero.
That's how this type of exception looks when thrown in Eclipse. The number in red signifies the index you tried to access. So the code would look like this:
myArray[5]
The error is thrown when you try to access an index which doesn't exist in that array. If an array has a length of 3,
int[] intArray = new int[3];
then the only valid indexes are:
intArray[0]
intArray[1]
intArray[2]
If an array has a length of 1,
int[] intArray = new int[1];
then the only valid index is:
intArray[0]
Any integer equal to the length of the array, or bigger than it: is out of bounds.
Any integer less than 0: is out of bounds;
P.S.: If you look to have a better understanding of arrays and do some practical exercises, there's a video here: tutorial on arrays in Java
For multidimensional arrays, it can be tricky to make sure you access the length property of the right dimension. Take the following code for example:
int [][][] a = new int [2][3][4];
for(int i = 0; i < a.length; i++){
for(int j = 0; j < a[i].length; j++){
for(int k = 0; k < a[j].length; k++){
System.out.print(a[i][j][k]);
}
System.out.println();
}
System.out.println();
}
Each dimension has a different length, so the subtle bug is that the middle and inner loops use the length property of the same dimension (because a[i].length is the same as a[j].length).
Instead, the inner loop should use a[i][j].length (or a[0][0].length, for simplicity).
For any array of length n, elements of the array will have an index from 0 to n-1.
If your program is trying to access any element (or memory) having array index greater than n-1, then Java will throw ArrayIndexOutOfBoundsException
So here are two solutions that we can use in a program
Maintaining count:
for(int count = 0; count < array.length; count++) {
System.out.println(array[count]);
}
Or some other looping statement like
int count = 0;
while(count < array.length) {
System.out.println(array[count]);
count++;
}
A better way go with a for each loop, in this method a programmer has no need to bother about the number of elements in the array.
for(String str : array) {
System.out.println(str);
}
ArrayIndexOutOfBoundsException whenever this exception is coming it mean you are trying to use an index of array which is out of its bounds or in lay man terms you are requesting more than than you have initialised.
To prevent this always make sure that you are not requesting a index which is not present in array i.e. if array length is 10 then your index must range between 0 to 9
ArrayIndexOutOfBounds means you are trying to index a position within an array that is not allocated.
In this case:
String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
System.out.println(name[i]);
}
name.length is 3 since the array has been defined with 3 String objects.
When accessing the contents of an array, position starts from 0. Since there are 3 items, it would mean name[0]="tom", name[1]="dick" and name[2]="harry
When you loop, since i can be less than or equal to name.length, you are trying to access name[3] which is not available.
To get around this...
In your for loop, you can do i < name.length. This would prevent looping to name[3] and would instead stop at name[2]
for(int i = 0; i<name.length; i++)
Use a for each loop
String[] name = { "tom", "dick", "harry" };
for(String n : name) {
System.out.println(n);
}
Use list.forEach(Consumer action) (requires Java8)
String[] name = { "tom", "dick", "harry" };
Arrays.asList(name).forEach(System.out::println);
Convert array to stream - this is a good option if you want to perform additional 'operations' to your array e.g. filter, transform the text, convert to a map etc (requires Java8)
String[] name = { "tom", "dick", "harry" };
--- Arrays.asList(name).stream().forEach(System.out::println);
--- Stream.of(name).forEach(System.out::println);
ArrayIndexOutOfBoundsException means that you are trying to access an index of the array that does not exist or out of the bound of this array. Array indexes start from 0 and end at length - 1.
In your case
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n'); // i goes from 0 to length, Not correct
}
ArrayIndexOutOfBoundsException happens when you are trying to access
the name.length indexed element which does not exist (array index ends at length -1). just replacing <= with < would solve this problem.
for(int i = 0; i < name.length; i++) {
System.out.print(name[i] +'\n'); // i goes from 0 to length - 1, Correct
}
According to your Code :
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
If You check
System.out.print(name.length);
you will get 3;
that mean your name length is 3
your loop is running from 0 to 3
which should be running either "0 to 2" or "1 to 3"
Answer
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
System.out.print(name[i] +'\n');
}
Each item in an array is called an element, and each element is accessed by its numerical index. As shown in the preceding illustration, numbering begins with 0. The 9th element, for example, would therefore be accessed at index 8.
IndexOutOfBoundsException is thrown to indicate that an index of some sort (such as to an array, to a string, or to a vector) is out of range.
Any array X, can be accessed from [0 to (X.length - 1)]
I see all the answers here explaining how to work with arrays and how to avoid the index out of bounds exceptions. I personally avoid arrays at all costs. I use the Collections classes, which avoids all the silliness of having to deal with array indices entirely. The looping constructs work beautifully with collections supporting code that is both easier to write, understand and maintain.
If you use an array's length to control iteration of a for loop, always remember that the index of the first item in an array is 0. So the index of the last element in an array is one less than the array's length.
ArrayIndexOutOfBoundsException name itself explains that If you trying to access the value at the index which is out of the scope of Array size then such kind of exception occur.
In your case, You can just remove equal sign from your for loop.
for(int i = 0; i<name.length; i++)
The better option is to iterate an array:
for(String i : name )
System.out.println(i);
This error is occurs at runs loop overlimit times.Let's consider simple example like this,
class demo{
public static void main(String a[]){
int[] numberArray={4,8,2,3,89,5};
int i;
for(i=0;i<numberArray.length;i++){
System.out.print(numberArray[i+1]+" ");
}
}
At first, I have initialized an array as 'numberArray'. then , some array elements are printed using for loop. When loop is running 'i' time , print the (numberArray[i+1] element..(when i value is 1, numberArray[i+1] element is printed.)..Suppose that, when i=(numberArray.length-2), last element of array is printed..When 'i' value goes to (numberArray.length-1) , no value for printing..In that point , 'ArrayIndexOutOfBoundsException' is occur.I hope to you could get idea.thank you !
You can use Optional in functional style to avoid NullPointerException and ArrayIndexOutOfBoundsException :
String[] array = new String[]{"aaa", null, "ccc"};
for (int i = 0; i < 4; i++) {
String result = Optional.ofNullable(array.length > i ? array[i] : null)
.map(x -> x.toUpperCase()) //some operation here
.orElse("NO_DATA");
System.out.println(result);
}
Output:
AAA
NO_DATA
CCC
NO_DATA
In most of the programming language indexes is start from 0.So you must have to write i<names.length or i<=names.length-1 instead of i<=names.length.
You could not iterate or store more data than the length of your array. In this case you could do like this:
for (int i = 0; i <= name.length - 1; i++) {
// ....
}
Or this:
for (int i = 0; i < name.length; i++) {
// ...
}

n nested for loops in a method with n as input

I have a function, and one of the inputs is the number of for loops that I need to do. In other words, the function is:
double MethodName(otherinputs, int numberofForLoops)
The number of for loops, however, is the number of nested forloops. In other words, if numberofForLoops = 3, then I would run
for(int i blah blah blah)
{
for(int j blah blah blah)
{
for(int k blah blah blah)
{ actual function }
}
}
How would I structure the method?
There is no way to do that directly. What you can do is use recursion, and make a single recursive call for each loop that you need (and have one loop in the method)
So if your actual function does not depend on i, j, k, you can substitute your n loops with just one.
for(int j blah^n){
actual function
}
The number of times it will be executed is the same as the number of times n nested loops will be executed.
The algorithm is very much like incrementing a Very Long Number (in a varied base BTW).
Since you have an undetermined amount of loops, you need to pass their count along with their limits:
ret_type do_loops(int numberOfForLoops, int limits[])
The do_loops function shall keep the current state in the similar array:
ret_type do_loops(int numberOfForLoops, int limits[]) {
int indices[numberOfForLoops] = { 0 };
and always try to increment the lowest possible dimension:
ret_type do_loops(int numberOfForLoops, int limits[]) {
int indices[numberOfForLoops] = { 0 };
int index = 0;
while (1) {
// Call with current index configuration
call_target_function(numberOfForLoops, indices);
// Increment current loop. If it overflows, propagate the carry
indices[index] += 1;
while (index < numberOfForLoops && indices[index] == limits[index]) {
indices[index] = 0;
index += 1;
}
// If the highest dimension overflown, you are done
if (index == numberOfForLoops) {
return ...;
}
// If some dimension successfully incremented, all dimensions below it were reset to 0
index = 0;
}

Nested For Loops Explanation Needed

Basically, in this program, I was instructed to create an array of random numbers and then sort them smallest to largest by bubble sorting with for loops. With a bunch of trial and error, my buddy and I were able to figure it out but I just took a look back at my code and honestly, it's very hard to comprehend.. I'm not too familiar with nested loops so if someone could explain how this method is working, that would be awesome. More specifically, what does the value j and i stand for.
public void sort() {
int val = 0;
for(int i = 0; i < myArray.length; i++) {
for(int j = 1; j < (myArray.length - i); j++) {
if(myArray[j-1] > myArray[j]) {
val = myArray[j-1];
myArray[j-1] = myArray[j];
myArray[j] = val;
}
}
}
}
Any answers are greatly appreciated, thanks guys/gals!
i and j are short with no inherent meaning other than to represent the index you are at in the array. The first for loop is so that the second loop and the sorting method are repeated for as many items are in the array. The second loop does the sorting.
if(myArray[j-1] > myArray[j]) { // Checks if the index `j` in the array is less than the one before it.
val = myArray[j-1]; // Temporarily stores the greater value.
myArray[j-1] = myArray[j]; // Swap the numbers.
myArray[j] = val; // Swap the numbers.
}

For VS Foreach on Array performance (in AS3/Flex)

Which one is faster? Why?
var messages:Array = [.....]
// 1 - for
var len:int = messages.length;
for (var i:int = 0; i < len; i++) {
var o:Object = messages[i];
// ...
}
// 2 - foreach
for each (var o:Object in messages) {
// ...
}
From where I'm sitting, regular for loops are moderately faster than for each loops in the minimal case. Also, as with AS2 days, decrementing your way through a for loop generally provides a very minor improvement.
But really, any slight difference here will be dwarfed by the requirements of what you actually do inside the loop. You can find operations that will work faster or slower in either case. The real answer is that neither kind of loop can be meaningfully said to be faster than the other - you must profile your code as it appears in your application.
Sample code:
var size:Number = 10000000;
var arr:Array = [];
for (var i:int=0; i<size; i++) { arr[i] = i; }
var time:Number, o:Object;
// for()
time = getTimer();
for (i=0; i<size; i++) { arr[i]; }
trace("for test: "+(getTimer()-time)+"ms");
// for() reversed
time = getTimer();
for (i=size-1; i>=0; i--) { arr[i]; }
trace("for reversed test: "+(getTimer()-time)+"ms");
// for..in
time = getTimer();
for each(o in arr) { o; }
trace("for each test: "+(getTimer()-time)+"ms");
Results:
for test: 124ms
for reversed test: 110ms
for each test: 261ms
Edit: To improve the comparison, I changed the inner loops so they do nothing but access the collection value.
Edit 2: Answers to oshyshko's comment:
The compiler could skip the accesses in my internal loops, but it doesn't. The loops would exit two or three times faster if it was.
The results change in the sample code you posted because in that version, the for loop now has an implicit type conversion. I left assignments out of my loops to avoid that.
Of course one could argue that it's okay to have an extra cast in the for loop because "real code" would need it anyway, but to me that's just another way of saying "there's no general answer; which loop is faster depends on what you do inside your loop". Which is the answer I'm giving you. ;)
When iterating over an array, for each loops are way faster in my tests.
var len:int = 1000000;
var i:int = 0;
var arr:Array = [];
while(i < len) {
arr[i] = i;
i++;
}
function forEachLoop():void {
var t:Number = getTimer();
var sum:Number = 0;
for each(var num:Number in arr) {
sum += num;
}
trace("forEachLoop :", (getTimer() - t));
}
function whileLoop():void {
var t:Number = getTimer();
var sum:Number = 0;
var i:int = 0;
while(i < len) {
sum += arr[i] as Number;
i++;
}
trace("whileLoop :", (getTimer() - t));
}
forEachLoop();
whileLoop();
This gives:
forEachLoop : 87
whileLoop : 967
Here, probably most of while loop time is spent casting the array item to a Number. However, I consider it a fair comparison, since that's what you get in the for each loop.
My guess is that this difference has to do with the fact that, as mentioned, the as operator is relatively expensive and array access is also relatively slow. With a for each loop, both operations are handled natively, I think, as opossed to performed in Actionscript.
Note, however, that if type conversion actually takes place, the for each version is much slower and the while version if noticeably faster (though, still, for each beats while):
To test, change array initialization to this:
while(i < len) {
arr[i] = i + "";
i++;
}
And now the results are:
forEachLoop : 328
whileLoop : 366
forEachLoop : 324
whileLoop : 369
I've had this discussion with a few collegues before, and we have all found different results for different scenarios. However, there was one test that I found quite eloquent for comparison's sake:
var array:Array=new Array();
for (var k:uint=0; k<1000000; k++) {
array.push(Math.random());
}
stage.addEventListener("mouseDown",foreachloop);
stage.addEventListener("mouseUp",forloop);
/////// Array /////
/* 49ms */
function foreachloop(e) {
var t1:uint=getTimer();
var tmp:Number=0;
var i:uint=0;
for each (var n:Number in array) {
i++;
tmp+=n;
}
trace("foreach", i, tmp, getTimer() - t1);
}
/***** 81ms ****/
function forloop(e) {
var t1:uint=getTimer();
var tmp:Number=0;
var l:uint=array.length;
for(var i:uint = 0; i < l; i++)
tmp += Number(array[i]);
trace("for", i, tmp, getTimer() - t1);
}
What I like about this tests is that you have a reference for both the key and value in each iteration of both loops (removing the key counter in the "for-each" loop is not that relevant). Also, it operates with Number, which is probably the most common loop that you will want to optimize that much. And most importantly, the winner is the "for-each", which is my favorite loop :P
Notes:
-Referencing the array in a local variable within the function of the "for-each" loop is irrelevant, but in the "for" loop you do get a speed bump (75ms instead of 105ms):
function forloop(e) {
var t1:uint=getTimer();
var tmp:Number=0;
var a:Array=array;
var l:uint=a.length;
for(var i:uint = 0; i < l; i++)
tmp += Number(a[i]);
trace("for", i, tmp, getTimer() - t1);
}
-If you run the same tests with the Vector class, the results are a bit confusing :S
for would be faster for arrays...but depending on the situation it can be foreach that is best...see this .net benchmark test.
Personally, I'd use either until I got to the point where it became necessary for me to optimize the code. Premature optimization is wasteful :-)
Maybe in a array where all element are there and start at zero (0 to X) it would be faster to use a for loop. In all other case (sparse array) it can be a LOT faster to use for each.
The reason is the usage of two data structure in the array: Hast table an Debse Array.
Please read my Array analysis using Tamarin source:
http://jpauclair.wordpress.com/2009/12/02/tamarin-part-i-as3-array/
The for loop will check at undefined index where the for each will skip those one jumping to next element in the HastTable
guys!
Especially Juan Pablo Califano.
I've checked your test. The main difference in obtain array item.
If you will put var len : int = 40000;, you will see that 'while' cycle is faster.
But it loses with big counts of array, instead for..each.
Just an add-on:
a for each...in loop doesn't assure You, that the elements in the array/vector gets enumerated in the ORDER THEY ARE STORED in them. (except XMLs)
This IS a vital difference, IMO.
"...Therefore, you should not write code that depends on a for-
each-in or for-in loop’s enumeration order unless you are processing
XML data..." C.Moock
(i hope not to break law stating this one phrase...)
Happy benchmarking.
sorry to prove you guys wrong, but for each is faster. even a lot. except, if you don't want to access the array values, but a) this does not make sense and b) this is not the case here.
as a result of this, i made a detailed post on my super new blog ... :D
greetz
back2dos

Most efficient way to sort parallel arrays in a restricted-feature language

The environment: I am working in a proprietary scripting language where there is no such thing as a user-defined function. I have various loops and local variables of primitive types that I can create and use.
I have two related arrays, "times" and "values". They both contain floating point values. I want to numerically sort the "times" array but have to be sure that the same operations are applied on the "values" array. What's the most efficient way I can do this without the benefit of things like recursion?
You could maintain an index table and sort the index table instead.
This way you will not have to worry about times and values being consistent.
And whenever you need a sorted value, you can lookup on the sorted index.
And if in the future you decided there was going to be a third value, the sorting code will not need any changes.
Here's a sample in C#, but it shouldn't be hard to adapt to your scripting language:
static void Main() {
var r = new Random();
// initialize random data
var index = new int[10]; // the index table
var times = new double[10]; // times
var values = new double[10]; // values
for (int i = 0; i < 10; i++) {
index[i] = i;
times[i] = r.NextDouble();
values[i] = r.NextDouble();
}
// a naive bubble sort
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
// compare time value at current index
if (times[index[i]] < times[index[j]]) {
// swap index value (times and values remain unchanged)
var temp = index[i];
index[i] = index[j];
index[j] = temp;
}
// check if the result is correct
for (int i = 0; i < 10; i++)
Console.WriteLine(times[index[i]]);
Console.ReadKey();
}
Note: I used a naive bubble sort there, watchout. In your case, an insertion sort is probably a good candidate. Since you don't want complex recursions.
Just take your favourite sorting algorithm (e.g. Quicksort or Mergesort) and use it to sort the "values" array. Whenever two values are swapped in "values", also swap the values with the same indices in the "times" array.
So basically you can take any fast sorting algorithm and modify the swap() operation so that elements in both arrays are swapped.
Take a look at the Bottom-Up mergesort at Algorithmist. It's a non-recursive way of performing a mergesort. The version presented there uses function calls, but that can be inlined easily enough.
Like martinus said, every time you change a value in one array, do the exact same thing in the parallel array.
Here's a C-like version of a stable-non-recursive mergesort that makes no function calls, and uses no recursion.
const int arrayLength = 40;
float times_array[arrayLength];
float values_array[arrayLength];
// Fill the two arrays....
// Allocate two buffers
float times_buffer[arrayLength];
float values_buffer[arrayLength];
int blockSize = 1;
while (blockSize <= arrayLength)
{
int i = 0;
while (i < arrayLength-blockSize)
{
int begin1 = i;
int end1 = begin1 + blockSize;
int begin2 = end1;
int end2 = begin2 + blockSize;
int bufferIndex = begin1;
while (begin1 < end1 && begin2 < end2)
{
if ( values_array[begin1] > times_array[begin2] )
{
times_buffer[bufferIndex] = times_array[begin2];
values_buffer[bufferIndex++] = values_array[begin2++];
}
else
{
times_buffer[bufferIndex] = times_array[begin1];
values_buffer[bufferIndex++] = values_array[begin1++];
}
}
while ( begin1 < end1 )
{
times_buffer[bufferIndex] = times_array[begin1];
values_buffer[bufferIndex++] = values_array[begin1++];
}
while ( begin2 < end2 )
{
times_buffer[bufferIndex] = times_array[begin2];
values_buffer[bufferIndex++] = values_array[begin2++];
}
for (int k = i; k < i + 2 * blockSize; ++k)
{
times_array[k] = times_buffer[k];
values_array[k] = values_buffer[k];
}
i += 2 * blockSize;
}
blockSize *= 2;
}
I wouldn't suggest writing your own sorting routine, as the sorting routines provided as part of the Java language are well optimized.
The way I'd solve this is to copy the code in the java.util.Arrays class into your own class i.e. org.mydomain.util.Arrays. And add some comments telling yourself not to use the class except when you must have the additional functionality that you're going to add. The Arrays class is quite stable so this is less, less ideal than it would seem, but it's still less than ideal. However, the methods you need to change are private, so you've no real choice.
You then want to create an interface along the lines of:
public static interface SwapHook {
void swap(int a, int b);
}
You then need to add this to the sort method you're going to use, and to every subordinate method called in the sorting procedure, which swaps elements in your primary array. You arrange for the hook to get called by your modified sorting routine, and you can then implement the SortHook interface to achieve the behaviour you want in any secondary (e.g. parallel) arrays.
HTH.

Resources