Using Java 8 stream methods to get the last max value

Multi tool use
Multi tool use












9















Given a list of items with properties, I am trying to get the last item to appear with a maximum value of said property.



For example, for the following list of objects:



t  i
A: 3
D: 7 *
F: 4
C: 5
X: 7 *
M: 6


I can get one of the Things with the highest i:



Thing t = items.stream()
.max(Comparator.comparingLong(Thing::getI))
.orElse(null);


However, this will get me Thing t = D. Is there a clean and elegant way of getting the last item, i.e. X in this case?



One possible solution is using the reduce function. However, the property is calculated on the fly and it would look more like:



Thing t = items.stream()
.reduce((left, right) -> {
long leftValue = valueFunction.apply(left);
long rightValue = valueFunction.apply(right);
return leftValue > rightValue ? left : right;
})
.orElse(null);


The valueFunction now needs to be called nearly twice as often.



Other obvious roundabout solutions are:




  1. Store the object in a Tuple with its index

  2. Store the object in a Tuple with its computed value

  3. Reverse the list beforehand

  4. Don't use Streams










share|improve this question





























    9















    Given a list of items with properties, I am trying to get the last item to appear with a maximum value of said property.



    For example, for the following list of objects:



    t  i
    A: 3
    D: 7 *
    F: 4
    C: 5
    X: 7 *
    M: 6


    I can get one of the Things with the highest i:



    Thing t = items.stream()
    .max(Comparator.comparingLong(Thing::getI))
    .orElse(null);


    However, this will get me Thing t = D. Is there a clean and elegant way of getting the last item, i.e. X in this case?



    One possible solution is using the reduce function. However, the property is calculated on the fly and it would look more like:



    Thing t = items.stream()
    .reduce((left, right) -> {
    long leftValue = valueFunction.apply(left);
    long rightValue = valueFunction.apply(right);
    return leftValue > rightValue ? left : right;
    })
    .orElse(null);


    The valueFunction now needs to be called nearly twice as often.



    Other obvious roundabout solutions are:




    1. Store the object in a Tuple with its index

    2. Store the object in a Tuple with its computed value

    3. Reverse the list beforehand

    4. Don't use Streams










    share|improve this question



























      9












      9








      9








      Given a list of items with properties, I am trying to get the last item to appear with a maximum value of said property.



      For example, for the following list of objects:



      t  i
      A: 3
      D: 7 *
      F: 4
      C: 5
      X: 7 *
      M: 6


      I can get one of the Things with the highest i:



      Thing t = items.stream()
      .max(Comparator.comparingLong(Thing::getI))
      .orElse(null);


      However, this will get me Thing t = D. Is there a clean and elegant way of getting the last item, i.e. X in this case?



      One possible solution is using the reduce function. However, the property is calculated on the fly and it would look more like:



      Thing t = items.stream()
      .reduce((left, right) -> {
      long leftValue = valueFunction.apply(left);
      long rightValue = valueFunction.apply(right);
      return leftValue > rightValue ? left : right;
      })
      .orElse(null);


      The valueFunction now needs to be called nearly twice as often.



      Other obvious roundabout solutions are:




      1. Store the object in a Tuple with its index

      2. Store the object in a Tuple with its computed value

      3. Reverse the list beforehand

      4. Don't use Streams










      share|improve this question
















      Given a list of items with properties, I am trying to get the last item to appear with a maximum value of said property.



      For example, for the following list of objects:



      t  i
      A: 3
      D: 7 *
      F: 4
      C: 5
      X: 7 *
      M: 6


      I can get one of the Things with the highest i:



      Thing t = items.stream()
      .max(Comparator.comparingLong(Thing::getI))
      .orElse(null);


      However, this will get me Thing t = D. Is there a clean and elegant way of getting the last item, i.e. X in this case?



      One possible solution is using the reduce function. However, the property is calculated on the fly and it would look more like:



      Thing t = items.stream()
      .reduce((left, right) -> {
      long leftValue = valueFunction.apply(left);
      long rightValue = valueFunction.apply(right);
      return leftValue > rightValue ? left : right;
      })
      .orElse(null);


      The valueFunction now needs to be called nearly twice as often.



      Other obvious roundabout solutions are:




      1. Store the object in a Tuple with its index

      2. Store the object in a Tuple with its computed value

      3. Reverse the list beforehand

      4. Don't use Streams







      java java-8 java-stream






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 53 mins ago









      nullpointer

      47.5k11100191




      47.5k11100191










      asked 1 hour ago









      DrucklesDruckles

      88211032




      88211032
























          6 Answers
          6






          active

          oldest

          votes


















          2














          Conceptually, you seem to be possibly looking for something like thenComparing using the index of the elements in the list:



          Thing t = items.stream()
          .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
          .orElse(null);





          share|improve this answer





















          • 1





            Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

            – nullpointer
            54 mins ago








          • 1





            I like this. 1+

            – Eugene
            35 mins ago



















          2














          To avoid the multiple applications of valueFunction in your reduce solution, simply explicitly calculate the result and put it in a tuple:



          Item lastMax = items.stream()
          .map(item -> new AbstractMap.SimpleEntry<Item, Long>(item, valueFunction.apply(item)))
          .reduce((l, r) -> l.getValue() > r.getValue() ? l : r )
          .map(Map.Entry::getKey)
          .orElse(null);





          share|improve this answer































            1














            Remove the equals option from the comparator (ie. write your own comparator that doesn't include an equals option):



            Thing t = items.stream()
            .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
            .orElse(null);





            share|improve this answer































              1














              Your current implementation using reduce looks good, unless your value-extractor function is costly.



              Considering later you may want to reuse the logic for different object types & fields, I would extract the logic itself in separate generic method/methods:



              public static <T, K, V> Function<T, Map.Entry<K, V>> toEntry(Function<T, K> keyFunc, Function<T, V> valueFunc){
              return t -> new AbstractMap.SimpleEntry<>(keyFunc.apply(t), valueFunc.apply(t));
              }

              public static <ITEM, FIELD extends Comparable<FIELD>> ITEM maxBy(Function<ITEM, FIELD> extractor, Collection<ITEM> items) {
              return items.stream()
              .map(toEntry(identity(), extractor))
              .max(comparing(Map.Entry::getValue))
              .map(Map.Entry::getKey)
              .orElse(null);
              }


              The code snippets above can be used like this:



              Thing maxThing =  maxBy(Thing::getField, things);

              AnotherThing maxAnotherThing = maxBy(AnotherThing::getAnotherField, anotherThings);





              share|improve this answer































                1














                You can still use the reduction to get this thing done. If t1 is larger, then only it will keep t1. In all the other cases it will keep t2. If either t2 is larger or t1 and t2 are the same, then it will eventually return t2 adhering to your requirement.



                Thing t = items.stream().
                reduce((t1, t2) -> t1.getI() > t2.getI() ? t1 : t2)
                .orElse(null);





                share|improve this answer


























                • There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                  – Druckles
                  1 hour ago



















                0














                Stream is not necessary bad if you do things in two steps :



                1) Find the i value that has more occurrences in the Iterable (as you did)

                2) Search the last element for this i value by starting from the end of items:



                Thing t = 
                items.stream()
                .max(Comparator.comparingLong(Thing::getI))
                .mapping(firstMaxThing ->
                ListIterator li = items.listIterator(items.size());
                while(li.hasPrevious()) {
                Thing current = li.previous()
                if (li.previous().getI() == firstMaxThing.getI()){
                return current;
                }
                }
                throw new RuntimeException("should not occur here if max was found");
                ).orElse(null)


                We could write it with StreamSupport to make it more elegant :



                Thing t =  
                items.stream()
                .max(Comparator.comparingLong(Thing::getI))
                .mapping(firstMaxThing ->
                Iterable<Thing> iterable = () -> items.listIterator(items.size());
                return
                StreamSupport.stream(iterable.spliterator(), false)
                .filter(i -> i.getI() == firstMaxThing.getI())
                .findFirst().get(); // here get() cannot fail as *max()* returned something.
                )
                .orElse(null)




                share























                  Your Answer






                  StackExchange.ifUsing("editor", function () {
                  StackExchange.using("externalEditor", function () {
                  StackExchange.using("snippets", function () {
                  StackExchange.snippets.init();
                  });
                  });
                  }, "code-snippets");

                  StackExchange.ready(function() {
                  var channelOptions = {
                  tags: "".split(" "),
                  id: "1"
                  };
                  initTagRenderer("".split(" "), "".split(" "), channelOptions);

                  StackExchange.using("externalEditor", function() {
                  // Have to fire editor after snippets, if snippets enabled
                  if (StackExchange.settings.snippets.snippetsEnabled) {
                  StackExchange.using("snippets", function() {
                  createEditor();
                  });
                  }
                  else {
                  createEditor();
                  }
                  });

                  function createEditor() {
                  StackExchange.prepareEditor({
                  heartbeatType: 'answer',
                  autoActivateHeartbeat: false,
                  convertImagesToLinks: true,
                  noModals: true,
                  showLowRepImageUploadWarning: true,
                  reputationToPostImages: 10,
                  bindNavPrevention: true,
                  postfix: "",
                  imageUploader: {
                  brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                  contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                  allowUrls: true
                  },
                  onDemand: true,
                  discardSelector: ".discard-answer"
                  ,immediatelyShowMarkdownHelp:true
                  });


                  }
                  });














                  draft saved

                  draft discarded


















                  StackExchange.ready(
                  function () {
                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54535632%2fusing-java-8-stream-methods-to-get-the-last-max-value%23new-answer', 'question_page');
                  }
                  );

                  Post as a guest















                  Required, but never shown

























                  6 Answers
                  6






                  active

                  oldest

                  votes








                  6 Answers
                  6






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes









                  2














                  Conceptually, you seem to be possibly looking for something like thenComparing using the index of the elements in the list:



                  Thing t = items.stream()
                  .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
                  .orElse(null);





                  share|improve this answer





















                  • 1





                    Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

                    – nullpointer
                    54 mins ago








                  • 1





                    I like this. 1+

                    – Eugene
                    35 mins ago
















                  2














                  Conceptually, you seem to be possibly looking for something like thenComparing using the index of the elements in the list:



                  Thing t = items.stream()
                  .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
                  .orElse(null);





                  share|improve this answer





















                  • 1





                    Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

                    – nullpointer
                    54 mins ago








                  • 1





                    I like this. 1+

                    – Eugene
                    35 mins ago














                  2












                  2








                  2







                  Conceptually, you seem to be possibly looking for something like thenComparing using the index of the elements in the list:



                  Thing t = items.stream()
                  .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
                  .orElse(null);





                  share|improve this answer















                  Conceptually, you seem to be possibly looking for something like thenComparing using the index of the elements in the list:



                  Thing t = items.stream()
                  .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
                  .orElse(null);






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 35 mins ago

























                  answered 57 mins ago









                  nullpointernullpointer

                  47.5k11100191




                  47.5k11100191








                  • 1





                    Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

                    – nullpointer
                    54 mins ago








                  • 1





                    I like this. 1+

                    – Eugene
                    35 mins ago














                  • 1





                    Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

                    – nullpointer
                    54 mins ago








                  • 1





                    I like this. 1+

                    – Eugene
                    35 mins ago








                  1




                  1





                  Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

                  – nullpointer
                  54 mins ago







                  Assuming: that for two objects if attribute I is equal that doesn't mean the objects are equal as well. In which case the indexOf would return same value always.

                  – nullpointer
                  54 mins ago






                  1




                  1





                  I like this. 1+

                  – Eugene
                  35 mins ago





                  I like this. 1+

                  – Eugene
                  35 mins ago













                  2














                  To avoid the multiple applications of valueFunction in your reduce solution, simply explicitly calculate the result and put it in a tuple:



                  Item lastMax = items.stream()
                  .map(item -> new AbstractMap.SimpleEntry<Item, Long>(item, valueFunction.apply(item)))
                  .reduce((l, r) -> l.getValue() > r.getValue() ? l : r )
                  .map(Map.Entry::getKey)
                  .orElse(null);





                  share|improve this answer




























                    2














                    To avoid the multiple applications of valueFunction in your reduce solution, simply explicitly calculate the result and put it in a tuple:



                    Item lastMax = items.stream()
                    .map(item -> new AbstractMap.SimpleEntry<Item, Long>(item, valueFunction.apply(item)))
                    .reduce((l, r) -> l.getValue() > r.getValue() ? l : r )
                    .map(Map.Entry::getKey)
                    .orElse(null);





                    share|improve this answer


























                      2












                      2








                      2







                      To avoid the multiple applications of valueFunction in your reduce solution, simply explicitly calculate the result and put it in a tuple:



                      Item lastMax = items.stream()
                      .map(item -> new AbstractMap.SimpleEntry<Item, Long>(item, valueFunction.apply(item)))
                      .reduce((l, r) -> l.getValue() > r.getValue() ? l : r )
                      .map(Map.Entry::getKey)
                      .orElse(null);





                      share|improve this answer













                      To avoid the multiple applications of valueFunction in your reduce solution, simply explicitly calculate the result and put it in a tuple:



                      Item lastMax = items.stream()
                      .map(item -> new AbstractMap.SimpleEntry<Item, Long>(item, valueFunction.apply(item)))
                      .reduce((l, r) -> l.getValue() > r.getValue() ? l : r )
                      .map(Map.Entry::getKey)
                      .orElse(null);






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered 14 mins ago









                      MikeFHayMikeFHay

                      3,13032035




                      3,13032035























                          1














                          Remove the equals option from the comparator (ie. write your own comparator that doesn't include an equals option):



                          Thing t = items.stream()
                          .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
                          .orElse(null);





                          share|improve this answer




























                            1














                            Remove the equals option from the comparator (ie. write your own comparator that doesn't include an equals option):



                            Thing t = items.stream()
                            .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
                            .orElse(null);





                            share|improve this answer


























                              1












                              1








                              1







                              Remove the equals option from the comparator (ie. write your own comparator that doesn't include an equals option):



                              Thing t = items.stream()
                              .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
                              .orElse(null);





                              share|improve this answer













                              Remove the equals option from the comparator (ie. write your own comparator that doesn't include an equals option):



                              Thing t = items.stream()
                              .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
                              .orElse(null);






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered 1 hour ago









                              jvdmrjvdmr

                              1184




                              1184























                                  1














                                  Your current implementation using reduce looks good, unless your value-extractor function is costly.



                                  Considering later you may want to reuse the logic for different object types & fields, I would extract the logic itself in separate generic method/methods:



                                  public static <T, K, V> Function<T, Map.Entry<K, V>> toEntry(Function<T, K> keyFunc, Function<T, V> valueFunc){
                                  return t -> new AbstractMap.SimpleEntry<>(keyFunc.apply(t), valueFunc.apply(t));
                                  }

                                  public static <ITEM, FIELD extends Comparable<FIELD>> ITEM maxBy(Function<ITEM, FIELD> extractor, Collection<ITEM> items) {
                                  return items.stream()
                                  .map(toEntry(identity(), extractor))
                                  .max(comparing(Map.Entry::getValue))
                                  .map(Map.Entry::getKey)
                                  .orElse(null);
                                  }


                                  The code snippets above can be used like this:



                                  Thing maxThing =  maxBy(Thing::getField, things);

                                  AnotherThing maxAnotherThing = maxBy(AnotherThing::getAnotherField, anotherThings);





                                  share|improve this answer




























                                    1














                                    Your current implementation using reduce looks good, unless your value-extractor function is costly.



                                    Considering later you may want to reuse the logic for different object types & fields, I would extract the logic itself in separate generic method/methods:



                                    public static <T, K, V> Function<T, Map.Entry<K, V>> toEntry(Function<T, K> keyFunc, Function<T, V> valueFunc){
                                    return t -> new AbstractMap.SimpleEntry<>(keyFunc.apply(t), valueFunc.apply(t));
                                    }

                                    public static <ITEM, FIELD extends Comparable<FIELD>> ITEM maxBy(Function<ITEM, FIELD> extractor, Collection<ITEM> items) {
                                    return items.stream()
                                    .map(toEntry(identity(), extractor))
                                    .max(comparing(Map.Entry::getValue))
                                    .map(Map.Entry::getKey)
                                    .orElse(null);
                                    }


                                    The code snippets above can be used like this:



                                    Thing maxThing =  maxBy(Thing::getField, things);

                                    AnotherThing maxAnotherThing = maxBy(AnotherThing::getAnotherField, anotherThings);





                                    share|improve this answer


























                                      1












                                      1








                                      1







                                      Your current implementation using reduce looks good, unless your value-extractor function is costly.



                                      Considering later you may want to reuse the logic for different object types & fields, I would extract the logic itself in separate generic method/methods:



                                      public static <T, K, V> Function<T, Map.Entry<K, V>> toEntry(Function<T, K> keyFunc, Function<T, V> valueFunc){
                                      return t -> new AbstractMap.SimpleEntry<>(keyFunc.apply(t), valueFunc.apply(t));
                                      }

                                      public static <ITEM, FIELD extends Comparable<FIELD>> ITEM maxBy(Function<ITEM, FIELD> extractor, Collection<ITEM> items) {
                                      return items.stream()
                                      .map(toEntry(identity(), extractor))
                                      .max(comparing(Map.Entry::getValue))
                                      .map(Map.Entry::getKey)
                                      .orElse(null);
                                      }


                                      The code snippets above can be used like this:



                                      Thing maxThing =  maxBy(Thing::getField, things);

                                      AnotherThing maxAnotherThing = maxBy(AnotherThing::getAnotherField, anotherThings);





                                      share|improve this answer













                                      Your current implementation using reduce looks good, unless your value-extractor function is costly.



                                      Considering later you may want to reuse the logic for different object types & fields, I would extract the logic itself in separate generic method/methods:



                                      public static <T, K, V> Function<T, Map.Entry<K, V>> toEntry(Function<T, K> keyFunc, Function<T, V> valueFunc){
                                      return t -> new AbstractMap.SimpleEntry<>(keyFunc.apply(t), valueFunc.apply(t));
                                      }

                                      public static <ITEM, FIELD extends Comparable<FIELD>> ITEM maxBy(Function<ITEM, FIELD> extractor, Collection<ITEM> items) {
                                      return items.stream()
                                      .map(toEntry(identity(), extractor))
                                      .max(comparing(Map.Entry::getValue))
                                      .map(Map.Entry::getKey)
                                      .orElse(null);
                                      }


                                      The code snippets above can be used like this:



                                      Thing maxThing =  maxBy(Thing::getField, things);

                                      AnotherThing maxAnotherThing = maxBy(AnotherThing::getAnotherField, anotherThings);






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered 37 mins ago









                                      ETOETO

                                      2,432626




                                      2,432626























                                          1














                                          You can still use the reduction to get this thing done. If t1 is larger, then only it will keep t1. In all the other cases it will keep t2. If either t2 is larger or t1 and t2 are the same, then it will eventually return t2 adhering to your requirement.



                                          Thing t = items.stream().
                                          reduce((t1, t2) -> t1.getI() > t2.getI() ? t1 : t2)
                                          .orElse(null);





                                          share|improve this answer


























                                          • There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                                            – Druckles
                                            1 hour ago
















                                          1














                                          You can still use the reduction to get this thing done. If t1 is larger, then only it will keep t1. In all the other cases it will keep t2. If either t2 is larger or t1 and t2 are the same, then it will eventually return t2 adhering to your requirement.



                                          Thing t = items.stream().
                                          reduce((t1, t2) -> t1.getI() > t2.getI() ? t1 : t2)
                                          .orElse(null);





                                          share|improve this answer


























                                          • There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                                            – Druckles
                                            1 hour ago














                                          1












                                          1








                                          1







                                          You can still use the reduction to get this thing done. If t1 is larger, then only it will keep t1. In all the other cases it will keep t2. If either t2 is larger or t1 and t2 are the same, then it will eventually return t2 adhering to your requirement.



                                          Thing t = items.stream().
                                          reduce((t1, t2) -> t1.getI() > t2.getI() ? t1 : t2)
                                          .orElse(null);





                                          share|improve this answer















                                          You can still use the reduction to get this thing done. If t1 is larger, then only it will keep t1. In all the other cases it will keep t2. If either t2 is larger or t1 and t2 are the same, then it will eventually return t2 adhering to your requirement.



                                          Thing t = items.stream().
                                          reduce((t1, t2) -> t1.getI() > t2.getI() ? t1 : t2)
                                          .orElse(null);






                                          share|improve this answer














                                          share|improve this answer



                                          share|improve this answer








                                          edited 36 mins ago

























                                          answered 1 hour ago









                                          Ravindra RanwalaRavindra Ranwala

                                          9,24031635




                                          9,24031635













                                          • There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                                            – Druckles
                                            1 hour ago



















                                          • There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                                            – Druckles
                                            1 hour ago

















                                          There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                                          – Druckles
                                          1 hour ago





                                          There is no t or getT() in this case, it's simply used as a label in this example. And it can't be used to order the Stream; it's the order of the items in the original list that is important.

                                          – Druckles
                                          1 hour ago











                                          0














                                          Stream is not necessary bad if you do things in two steps :



                                          1) Find the i value that has more occurrences in the Iterable (as you did)

                                          2) Search the last element for this i value by starting from the end of items:



                                          Thing t = 
                                          items.stream()
                                          .max(Comparator.comparingLong(Thing::getI))
                                          .mapping(firstMaxThing ->
                                          ListIterator li = items.listIterator(items.size());
                                          while(li.hasPrevious()) {
                                          Thing current = li.previous()
                                          if (li.previous().getI() == firstMaxThing.getI()){
                                          return current;
                                          }
                                          }
                                          throw new RuntimeException("should not occur here if max was found");
                                          ).orElse(null)


                                          We could write it with StreamSupport to make it more elegant :



                                          Thing t =  
                                          items.stream()
                                          .max(Comparator.comparingLong(Thing::getI))
                                          .mapping(firstMaxThing ->
                                          Iterable<Thing> iterable = () -> items.listIterator(items.size());
                                          return
                                          StreamSupport.stream(iterable.spliterator(), false)
                                          .filter(i -> i.getI() == firstMaxThing.getI())
                                          .findFirst().get(); // here get() cannot fail as *max()* returned something.
                                          )
                                          .orElse(null)




                                          share




























                                            0














                                            Stream is not necessary bad if you do things in two steps :



                                            1) Find the i value that has more occurrences in the Iterable (as you did)

                                            2) Search the last element for this i value by starting from the end of items:



                                            Thing t = 
                                            items.stream()
                                            .max(Comparator.comparingLong(Thing::getI))
                                            .mapping(firstMaxThing ->
                                            ListIterator li = items.listIterator(items.size());
                                            while(li.hasPrevious()) {
                                            Thing current = li.previous()
                                            if (li.previous().getI() == firstMaxThing.getI()){
                                            return current;
                                            }
                                            }
                                            throw new RuntimeException("should not occur here if max was found");
                                            ).orElse(null)


                                            We could write it with StreamSupport to make it more elegant :



                                            Thing t =  
                                            items.stream()
                                            .max(Comparator.comparingLong(Thing::getI))
                                            .mapping(firstMaxThing ->
                                            Iterable<Thing> iterable = () -> items.listIterator(items.size());
                                            return
                                            StreamSupport.stream(iterable.spliterator(), false)
                                            .filter(i -> i.getI() == firstMaxThing.getI())
                                            .findFirst().get(); // here get() cannot fail as *max()* returned something.
                                            )
                                            .orElse(null)




                                            share


























                                              0












                                              0








                                              0







                                              Stream is not necessary bad if you do things in two steps :



                                              1) Find the i value that has more occurrences in the Iterable (as you did)

                                              2) Search the last element for this i value by starting from the end of items:



                                              Thing t = 
                                              items.stream()
                                              .max(Comparator.comparingLong(Thing::getI))
                                              .mapping(firstMaxThing ->
                                              ListIterator li = items.listIterator(items.size());
                                              while(li.hasPrevious()) {
                                              Thing current = li.previous()
                                              if (li.previous().getI() == firstMaxThing.getI()){
                                              return current;
                                              }
                                              }
                                              throw new RuntimeException("should not occur here if max was found");
                                              ).orElse(null)


                                              We could write it with StreamSupport to make it more elegant :



                                              Thing t =  
                                              items.stream()
                                              .max(Comparator.comparingLong(Thing::getI))
                                              .mapping(firstMaxThing ->
                                              Iterable<Thing> iterable = () -> items.listIterator(items.size());
                                              return
                                              StreamSupport.stream(iterable.spliterator(), false)
                                              .filter(i -> i.getI() == firstMaxThing.getI())
                                              .findFirst().get(); // here get() cannot fail as *max()* returned something.
                                              )
                                              .orElse(null)




                                              share













                                              Stream is not necessary bad if you do things in two steps :



                                              1) Find the i value that has more occurrences in the Iterable (as you did)

                                              2) Search the last element for this i value by starting from the end of items:



                                              Thing t = 
                                              items.stream()
                                              .max(Comparator.comparingLong(Thing::getI))
                                              .mapping(firstMaxThing ->
                                              ListIterator li = items.listIterator(items.size());
                                              while(li.hasPrevious()) {
                                              Thing current = li.previous()
                                              if (li.previous().getI() == firstMaxThing.getI()){
                                              return current;
                                              }
                                              }
                                              throw new RuntimeException("should not occur here if max was found");
                                              ).orElse(null)


                                              We could write it with StreamSupport to make it more elegant :



                                              Thing t =  
                                              items.stream()
                                              .max(Comparator.comparingLong(Thing::getI))
                                              .mapping(firstMaxThing ->
                                              Iterable<Thing> iterable = () -> items.listIterator(items.size());
                                              return
                                              StreamSupport.stream(iterable.spliterator(), false)
                                              .filter(i -> i.getI() == firstMaxThing.getI())
                                              .findFirst().get(); // here get() cannot fail as *max()* returned something.
                                              )
                                              .orElse(null)





                                              share











                                              share


                                              share










                                              answered 7 mins ago









                                              davidxxxdavidxxx

                                              65.8k66494




                                              65.8k66494






























                                                  draft saved

                                                  draft discarded




















































                                                  Thanks for contributing an answer to Stack Overflow!


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.




                                                  draft saved


                                                  draft discarded














                                                  StackExchange.ready(
                                                  function () {
                                                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54535632%2fusing-java-8-stream-methods-to-get-the-last-max-value%23new-answer', 'question_page');
                                                  }
                                                  );

                                                  Post as a guest















                                                  Required, but never shown





















































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown

































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown







                                                  4,0wqNYqw,foO6PO2pF7uXxQIOS8NmZmpzo0qa zETZF,DYDeilmGm
                                                  Fx,5,zcJs9wdcclU3lEFucBn0DSaQZfPGJj98M eUX mdtT1hf8N3sfaX7QgHrFmVBXbMI,8EebNZRtHVQDPQ6MI TVjG7Jtzi

                                                  Popular posts from this blog

                                                  Xianyang

                                                  Transaction terminated running SELECT on secondary AG group

                                                  Justizvollzugsanstalt Augsburg-Gablingen