HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Finding all indices of largest value in an array

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
indicesallarrayvaluelargestfinding

Problem

I have the following code that gives me the indices of an array's largest value:

public static void main(String[] args) {

    float[] elementList = new float[7];
    elementList[0] = 8F;
    elementList[1] = 5F;
    elementList[2] = 4F;
    elementList[3] = 3F;
    elementList[4] = 0F;
    elementList[5] = 8F;
    elementList[6] = 6F;
    // findLargestNumberLocations(elementList);
    largestNumbers(elementList);
}

private static void largestNumbers(float[] numbers) {

    float largeNumber = numbers[0];
    for (int i = 0; i  largeNumber) {
            largeNumber = numbers[i];
        }
    }
    for (int j = 0; j < numbers.length; j++) {
        if(largeNumber == numbers[j]){
            System.out.println("largest number index "+j);
        }
    }
}


Is there any optimized way of doing this?

Solution

In this case, your performance will not be terrible, but, for really large arrays you may run in to problems.

Also, there is a bug in your code... what if the input array is empty? Then you will get an ArrayIndexOutOfBoundsException on:

float largeNumber = numbers[0];


There is always more than one way to do things, but, I want to post an answer here because one possible solution (which may or may not be faster than your solution depending on data size) has a really close relationship to another CodeReview question posted recently. When I answered that question I could only think of artifical examples of when it was 'right' to use pre/post-increments. This is a good example of when....

See this answer here: Is it bad practice to increment more than one variable in a for loop declaration?

So, here is a good example of how and when a count and an index are related in a for loop and the way they can be incremented. I have some notes at the end:

private static int[] findLargeNumberIndices(float[] numbers) {

    // create an array of at least 8 members.
    // We may need to make this bigger during processing in case
    // there's more than 8 values with the same large value
    int[] indices = new int[Math.max(numbers.length / 16 , 8)];
    // how many large values do we have?
    int count = 0;
    // what is the largest value we have?
    float largeNumber = Float.NEGATIVE_INFINITY;
    for (int i = 0; i  largeNumber) {
            // we have a new large number value... reset our history....
            largeNumber = numbers[i];
            // setting count to zero is enough to 'clear' our previous references.
            count = 0;
            // we know there's space for at least index 0. No need to check.
            // note how we post-increment - this is a 'pattern'.
            indices[count++] = i;
        } else if (numbers[i] == largeNumber) {
            // we have another large value.
            if (count == indices.length) {
                // need to make more space for indices... increase array by 25%
                // count >>> 2 is the same as count / 4 ....
                indices = Arrays.copyOf(indices, count + (count >>> 2));
            }
            // again, use the post-increment
            indices[count++] = i;
        }
    }
    // return the number of values that are valid only.
    return Arrays.copyOf(indices, count);
}


Notes about this code:

  • The presentation (System.out.println(...)) is now outside the method.



  • It allocates a 'small' array to store the indexes. This array will grow if needed.



  • I picked 'good enough initial size for the array.... but some playing with the numbers may help performance.



  • There is no real reason to believe that this code is faster than the two loops - creating the array may be more expensive than the second loops.



  • note how the i index is incemented in the for-loop, but the count` is post-incremented each time it is used in the array.

Code Snippets

float largeNumber = numbers[0];
private static int[] findLargeNumberIndices(float[] numbers) {

    // create an array of at least 8 members.
    // We may need to make this bigger during processing in case
    // there's more than 8 values with the same large value
    int[] indices = new int[Math.max(numbers.length / 16 , 8)];
    // how many large values do we have?
    int count = 0;
    // what is the largest value we have?
    float largeNumber = Float.NEGATIVE_INFINITY;
    for (int i = 0; i < numbers.length; i++) {
        if (numbers[i] > largeNumber) {
            // we have a new large number value... reset our history....
            largeNumber = numbers[i];
            // setting count to zero is enough to 'clear' our previous references.
            count = 0;
            // we know there's space for at least index 0. No need to check.
            // note how we post-increment - this is a 'pattern'.
            indices[count++] = i;
        } else if (numbers[i] == largeNumber) {
            // we have another large value.
            if (count == indices.length) {
                // need to make more space for indices... increase array by 25%
                // count >>> 2 is the same as count / 4 ....
                indices = Arrays.copyOf(indices, count + (count >>> 2));
            }
            // again, use the post-increment
            indices[count++] = i;
        }
    }
    // return the number of values that are valid only.
    return Arrays.copyOf(indices, count);
}

Context

StackExchange Code Review Q#37201, answer score: 8

Revisions (0)

No revisions yet.