7

In a Java program, I have a class WaterBody in which one of the attributes is a double for electric power output. How can I find the maximum electric power output value in an array of WaterBody instances?

Here's my prototype:

public static WaterBody mostPowerful(WaterBody[] waterBodies) {

}

Attribute is electricPower and I have the getter method getElectricPower

Thanks in advance.

2
  • 1
    docs.oracle.com/javase/6/docs/api/java/util/…, java.util.Comparator) Commented Feb 8, 2016 at 23:34
  • Homework? Declare a variable maxval to store the object with the maximum value, iterate over the array with foreach, call getElectricPower() on each object and compare its value with the value from the object in your variable. If it is greater it is your new maximum object (assign it to maxval). Try to code it yourself, it can be fun! Show your code if it doesn't work out immediately Commented Feb 8, 2016 at 23:37

3 Answers 3

12

If you're using Java 8, you can write this as a one-liner:

public static WaterBody mostPowerful(WaterBody[] waterBodies) {
    return Arrays.stream(waterBodies)
            .max(Comparator.comparingDouble(WaterBody::getElectricPower))
            .orElseThrow(NoSuchElementException::new);
}

The orElseThrow(NoSuchElementException::new) causes a NoSuchElementException to be thrown if the incoming array is empty (and thus there is no maximum value). If you want to return null instead, use orElse(null).

Sign up to request clarification or add additional context in comments.

4 Comments

uh, look at that fancy stream ;) definitely the nicest solution if performance is not a big issue!
@Neuron To test your claim of "if performance is not a big issue", I decided to write a little program to test the various solution approaches. There are some surprising results in there....
On my computer, from fastest to slowest: nullable (2.4 ms), collections (3.1 ms), stream (4.6 ms), optional double (5.7 ms), optional (15.8 ms). The optional double and optional results actually surprised me a lot.
Worst-case (elements in ascending order) performance on my computer: nullable (2.2 ms), collections (3.2 ms), stream (4.6 ms), optional double (8.5 ms), optional (17.6 ms). This appreciably slowed down the optional double and optional results!
4

I am afraid you'll have to do a linear search:

public static WaterBody mostPowerful(WaterBody[] waterBodies) {
    double maxValue = -1;
    int indexOfMaxValue = -1;
    for(int i = 0; i < waterBodies.length; i++) {
        if(waterBodies[i].getElectricPower() > maxValue) {
            indexOfMaxValue = i;
        }
    }
    return waterBodies[indexOfMaxValue];
}

A more elegant solution can be achieved by using a Comparator. It defines an Interface, which tells if one object is "bigger" or "smaller" than another. You can define a Comparator like that:

Comparator<String> cmp = new Comparator<WaterBody>() {
    @Override
    public int compare(WaterBody o1, WaterBody o2) {
        return Double.compare(o1.getElectricPower(), o2.getElectricPower());
    }
};

If you'll need do operations like these often, it is advised to have a collection which always keeps it's content sorted, like a TreeSet It would be a lot smarter to use a collection, which keeps it's content sorted.

TreeSet<WaterBody> waterBodiesTree = new TreeSet<>(cmp);
Collections.addAll(waterBodiesTree, waterBodies);
WaterBody smallest = waterBodiesTree.first();
WaterBody biggest = waterBodiesTree.last();

If you only need to sort your array, the first example I used turns into a one-liner (using the same Comparator as defined earlier):

public static WaterBody mostPowerful(WaterBody[] waterBodies) {
    return Collections.max(waterbodies, cmp);
}

6 Comments

Manual searching is not necessary. You can use Collections.max as suggested by Steve Kuo, or in Java 8, use Arrays.stream to convert the array into a stream, then call Stream.max.
Apart from the typo on "waterbodies" on the if statement, that does the trick. Will look about collections though. Thanks! :)
@Chris Jester-Young I will add it to my post, but keep in mind that knowing how to do the very basics (like finding the maximum in a list) should come before learning how to let everything be handled by built in code. At university we learned to do these things the hard way first and I guess for a good reason. But I'll add it to the answer for curious readers
@Neuron On the contrary, in professional code (which I always assume questions on SO are about, unless the OP says otherwise) it's important to use library code rather than reinventing the wheel. :-)
@Chris Jester-Young I guess I pretty much overachieved all needs now :P
|
3

You can define a comparator in the WaterBody class

class WaterBody {
  :
  public static final Comparator<WaterBody> POWER_COMPARATOR =
    new Comparator<WaterBody>() {
      public int compare(WaterBody dev1, WaterBody dev2) {
        return Double.compare(dev1.getPower(), dev2.getPower());
      }
  };  
}

and use it as below

 WaterBody device = Collections.max(devices, WaterBody.POWER_COMPARATOR);

2 Comments

Double.compare(dev1.getElectricPower(), dev2.getElectricPower()) is still a more elegant solution. Not only is it easier to read, it also doesn't create two new objects for the stack.
Thank you for suggestion, included.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.