-3

What's the best & concise way to change the code given below in Java 8:

static int[] breakingRecords(int[] scores) {
    int lowest = 0, highest = 0, countlow = 0, counthigh = 0;
    for (int i = 0; i < scores.length; i++) {
        if (i == 0) {
            lowest = scores[0];
            highest = scores[0];
        } else {
            if (scores[i] < lowest) {
                lowest = scores[i];
                countlow++;
            } else if (scores[i] > highest) {
                highest = scores[i];
                counthigh++;
            }
        }
    }
    int rc[] = {counthigh, countlow};
    return rc;
}

Note: I know that I can use:

IntStream.range(0, 10).forEach(
    i -> {
      if (i == 0) {
            ...
    }

But to do so, I need to declare all the variables as AtomicInteger which makes the code verbose & hard to read.

There must be a better way than using AtomicIntegers. Is there?

DilTeam
  • 2,551
  • 9
  • 42
  • 69
  • what *scores[]* contains ? – Leviand Jul 23 '18 at 06:58
  • why would you need `AtomicInteger`s? – Maurice Perry Jul 23 '18 at 06:59
  • 2
    Please describe what the code is doing. We can only assignments and increments, but not what it's trying to do or what value is actually being computed – ernest_k Jul 23 '18 at 06:59
  • 1
    Can you explain what you need `countHigh` and `countLow` for? The snippet does not show how they're used, and without them, it's pretty each to implement with a stream. – Mureinik Jul 23 '18 at 07:00
  • 1
    `Arrays.stream(array).max()` and `Arrays.stream(array).min()` – Lino Jul 23 '18 at 07:04
  • Possible duplicate of [Concise way to get both min and max value of Java 8 stream](https://stackoverflow.com/questions/41816264/concise-way-to-get-both-min-and-max-value-of-java-8-stream) – Mario Ishac Jul 23 '18 at 07:06
  • To understand what this code is doing refer to this question on Hackerrank: https://www.hackerrank.com/challenges/breaking-best-and-worst-records/problem By the way, it PASSES ALL TEST CASES. Just trying to learn how to do this in Java 8. – DilTeam Jul 23 '18 at 07:18
  • 1
    Please [edit] your question with every information needed, don't uses links. I don't have access to every website due to a security protocol where I work. So include every in the question, it is the best way to get what you need ;) – AxelH Jul 23 '18 at 07:26
  • The question is currently on hold, therefore i will reply on the comments section. What you can do is stream over the input array to get an `IntStream`, from there you can call the `summaryStatistics` method to get an `IntSummaryStatistics` object. Finally, you call the `getMin` and `getMax` methods to get your breaking records. `final IntSummaryStatistics statistics = IntStream.of(scores).summaryStatistics(); final int[] rc = { statistics.getMin(), statistics.getMax() };` – marsouf Jul 23 '18 at 09:39

3 Answers3

4

Let's be much more simpler. You are getting the maximum and minimum values in a Stream.

IntStream provides method for that :

OptionalInt max()
OptionalInt min()

Here is a quick way of how to use it :

int[] array = {5, 6, 10, 2, 5};

OptionalInt max = Arrays.stream(array).max();
OptionalInt min = Arrays.stream(array).min();

System.out.println("min : " + min.getAsInt());
System.out.println("max : " + max.getAsInt());

Note that you get OptionalInt, so you should check for empty values, but this only occurs if the IntStream itself is empty. So you can check that before you even read the array.

EDIT: this solution was proposed before the question include the return showing that the important part is the countHigh and countLow part.

AxelH
  • 14,325
  • 2
  • 25
  • 55
  • I am not trying to simply get Min, Max!! To understand what this code is doing refer to this question on Hackerrank: hackerrank.com/challenges/breaking-best-and-worst-records/… By the way, it PASSES ALL TEST CASES. Just trying to learn how to do this in Java 8. – DilTeam Jul 23 '18 at 07:19
  • @DilTeam I don't go outside of stackoverflow for a question. Sorry but that's like not talking to strangers ;) And yes, what you are doing is getting the min an max of an array. Except that you also increment a value that doesn't seems useful (prooved by the tests cases passed). You can edit your question if you want. – AxelH Jul 23 '18 at 07:22
  • 3
    @GhostCat it was not when I wrote this ;) I have just notice the return that was added. So I have edited my part to. – AxelH Jul 23 '18 at 07:44
  • Well, that left a bit of option space for my answer, so fine with me. – GhostCat Jul 23 '18 at 07:44
  • 1
    I am not going to edit my answer to match the edit @GhostCat . This is the kind of edition that completly ruin answers but that's fine. I let yours mentionning why this is not always a good think to use `Stream` (this would be my side too now that I see what is needed...) – AxelH Jul 23 '18 at 07:46
2

Assuming that "the best way" actually refers to the most performant way ... you are probably already there (or very close to it)!

You see, using IntStream and lambdas might help with readability, but that will not magically increase performance. To the contrary. These constructs come with a certain amount of overhead!

In other words: if your ultimate goal is to write the code that solves the underlying problem in the most efficient way, then "old school" is (most likely) your best option.

Streams play nicely for readability (when used wisely), and they can help with efficient filtering and such, and of course, when using parallelStream() you might be able to get results quicker (by using more threads). But for straight forward simple computations on some array of ints, none of these advantages apply!

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • THANK YOU. That's what I was wondering. In this particular case, where we have to increment a counter outside Lambda, it seems **doing it the old fashioned way is better for readability & performance** ! This is the kinda of confirmation I was looking for from the experts. Sadly, I have got -5 for a question that's fair. Oh well... – DilTeam Jul 23 '18 at 14:52
0

You could achieve that by using a custom comparator, which accepts a predicate when to increment the counter and an access method to be able to get said counter:

public class IncrementingComparator implements Comparator<Integer>{
    private final IntPredicate doIncrement;
    private int count;

    public IncrementingComparator(IntPredicate doIncrement){
        this.doIncrement = doIncrement;
    }

    @Override
    public int compare(Integer o1, Integer o2){
        final int compareResult = o1.compareTo(o2);
        if(doIncrement.test(compareResult)){
            count++;
        }
        return compareResult;
    }

    public int count(){
        return count;
    }
}

You then could create 2 instances of above class:

final IncrementingComparator maxCmp = new IncrementingComparator(i -> i > 0);
final IncrementingComparator minCmp = new IncrementingComparator(i -> i < 0);

Which then can be used inside the min() and max() operations of Stream:

final Optional<Integer> max = Arrays.stream(array)
    .boxed()
    .max(maxCmp);
final Optional<Integer> min = Arrays.stream(array)
    .boxed()
    .min(minCmp);

After the min and max are found, you could then extract the count values from each comparator:

final int maxCount = maxCmp.count();
final int minCount = minCmp.count();

Note: Because the Comparators have an internal state, they can only be used once. (Or one could add a reset() method to set the count variable back to 0.

AxelH
  • 14,325
  • 2
  • 25
  • 55
Lino
  • 19,604
  • 6
  • 47
  • 65
  • How is this more concise? This looks a lot harder to read that the "old fashioned way". We shouldn't be using new features of a language just because they are cool... IMHO. – DilTeam Jul 23 '18 at 14:46