Goldbones
Goldbones

Reputation: 1457

How to remove First element based on condition using Stream

Imagine that I have this list of integers

List<Integer> myList= Arrays.asList(1,2,3,4,4);

Now I want to sum this elements excluding the first max value:

int sumExcludeMax = myList.stream()
            .filter(x -> x != Collections.max(list))
            .mapToInt(Integer::intValue)
            .sum();

In this way it's excluding all 4 in the list. How can I exclude just the first one using for instance .findFirst()?

Upvotes: 1

Views: 1497

Answers (3)

NoDataFound
NoDataFound

Reputation: 11959

You should not invoke max each time: Collections.max(myList) is evaluated for each item in myList while the list is not mutating (I assumed that you computed the max of the same list and that Collection.max(list) was a typo):

And for your question, if you want to sum all but the first max, then I think this works:

int sumExcludeMax = myList.stream().mapToInt(Integer::intValue).sum()
                  - Collections.max(myList);
  • Sum of 1,2,3,4,4 is: 14.
  • Max is 4, removing it once make it 10.

Since you are computing a IntStream, you can also summarize (I'm using Java 11 here, but it works with 8 apart from the var stuff):

var ss = myList.stream().mapToInt(Integer::intValue).summaryStatistics();
long result = ss.sum() - ss.max();

Upvotes: 4

ernest_k
ernest_k

Reputation: 45319

You can sort in reverse order, then skip one element:

int result = myList.stream()
               .sorted(Comparator.reverseOrder())
               .skip(1)
               .mapToInt(Integer::valueOf)
               .sum();

If you're on Java 12+, you can use Collectors.teeing in a different approach, computing the max in the first downstream, the sum in the second, and then the difference to work out the result:

int result = myList.stream()
        .collect(Collectors.teeing(
                   Collectors.maxBy(Integer::compare),
                   Collectors.summingInt(Integer::intValue), 
                   (v1, v2) -> v2 - v1.orElse(0)));

Both of these options yield 10.

Upvotes: 3

Maxdola
Maxdola

Reputation: 1650

If you use .distinct() in the stream object then you only get the max once, but also every other number only once, if you need the other numbers as duplicates it gets a bit more complicated.

List<Integer> myList= Arrays.asList(1,2,3,4,4);
int sumExcludeMax = myList.stream().distinct()
   .mapToInt(Integer::intValue)
   .sum();

This works if you need the other dublicates:

List<Integer> myList= Arrays.asList(1,2,3,4,4);
int sumExcludeMax = myList.stream()
      .filter(x -> x != Collections.max(myList))
      .mapToInt(Integer::intValue)
      .sum() + Collections.max(myList);

Upvotes: 1

Related Questions