• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • paul wheaton
  • Ron McLeod
  • Devaka Cooray
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Piet Souris
Bartenders:

Using Streams to find max value of a List of Objects

 
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hallo again, I find it difficult to accomplish this task as a noob with Streams.

Having a list of Items, each item has a value and a name. Using Streams, how can I get the item or items with the max value?

And another question, again using Streams, how can I remove those items having the max value?

Thanks in advance.
 
Marshal
Posts: 80613
467
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Adding you to our Streams forum.

Whatever you are doing, if you want a maximum value, you need some way to compare those values to decide whether,
  • value1 is “greater than” value2, or
  • value1 is “less than” value2, or
  • value1 is “the same as” value2.
  • I suggest you go through the Collections part of the Java™ Tutorials, particularly looking at the section called, “Object Ordering”. Then come back when you have understood that section and decided how to order any two of your objects.

    Do your objects have a “natural ordering”? That means that every two objects fulfil the three bullet points above, and that if you don't change anything you get the same results, and there is one single criterion used for the ordering. Some kinds of object have multiple possible orderings.
     
    Campbell Ritchie
    Marshal
    Posts: 80613
    467
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Have you been through the methods of the Stream interface? I think you will find something useful if you go through the names of all the methods.
     
    Sheriff
    Posts: 28394
    100
    Eclipse IDE Firefox Browser MySQL Database
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sot Nikele wrote:And another question, again using Streams, how can I remove those items having the max value?



    Streams aren't generally meant to modify the object from which they are streaming their data. Instead of trying to fight against that principle, I would say you are better off producing a new List<Item> which contains only those items which don't have the max value.

    This would require one Stream which produces the max value, and then a second Stream which filters objects which don't have the max value into that new list.
     
    Bartender
    Posts: 2447
    13
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Sot,
    You may consider using stream's max and Comparator:
    https://www.baeldung.com/java-collection-min-max
     
    Greenhorn
    Posts: 5
    1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I know you said you start stream and i don't wanna scare you but you can do it like this.
    I use parallelStream() instead of stream() because i wanna trigger *1 for myself. (*1 is new to me)

     
    Campbell Ritchie
    Marshal
    Posts: 80613
    467
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Welcome to the Ranch

    That code looks surprisingly complicated; there must ba an easier way to do it.
     
    Saloon Keeper
    Posts: 5613
    214
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    hi Mehmet,

    as Campbell writes, thre are easier ways to achieve the result, but I surely like your method.

    You could make the code a little more readable by creating two BiConsumers:

    and

    and use these in your '.collect'.

    Another way to shorten your code is to have

    I used your idea, but instead of creating an ArrayList with the maximum objects, I created a TreeMap<Integer, List<Object>>, so that that map's lastEntry gives us the max objects.
    For that I created a record and a helper class to keep the typing to a minimum:

    Using the 3-parameter version of collect, I needed, as you did, to write a BiConsumer<Short, Mehmet>, and a BiConsumer<Short, Short>. Since
    you are using a parallelStream, that last one was a little nasty.
    Well, I hope you find this instructive:

    And have a cow for your code!
     
    Bartender
    Posts: 15741
    368
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I find your code extremely confusing Piet. Please don't use existing type names for custom types. The name Short to me means java.lang.Short, which is the primitive wrapper type for the short integral type. It took me a while to realize it was a kind of type alias for a Map instead.

    I'm also not a fan of declaring variables to hold functional types. Instead, just write a private method instead of a lambda expression and use a method reference.

    Don't use method references or lambdas to refer to a method of a functional type. Pass the function object directly. In your code, you use sup::get in collect(), while passing sup directly will suffice.

    Note that your collection operation can be replaced by just the following:

    Or, if you want improved performance at the cost of losing encounter order:

    The second option still maintains correct ordering of the keys, so you can still use lastEntry() to get the list of maximum elements, the list itself just won't maintain encounter order.

    Now, if I didn't have access to the groupingBy() collector, I would write the code like this:

    As you can see, the accumulate() and combine() methods closely resemble your consumers, except I made them into methods on a local Accumulation class.

    This collector can easily be used in your main method and gives the exact same results as your original code:
     
    Piet Souris
    Saloon Keeper
    Posts: 5613
    214
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Well, if YOU say it's confusing,  then I guess it must be.

    As you can see, I did use the groupingBy in an earlier example, but here I followed OP's way with the .collect(supplier...), involving two BiConsumers.

    And I like using variables for functional interfaces, makes the code much more readable. You are right about my Short; can't remember ever having used a Short, I guess I forgot its existance. But the name 'Short'  instead of ' TreeMap<integer, List<Mehmet>> seemed very reasonable.

    But as said, point was to use the 3-parameter version of collect, something that you don't see too often.
     
    Stephan van Hulst
    Bartender
    Posts: 15741
    368
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I will admit that most of it comes down to personal preference. The only serious gripe I had was the Short thing.

    If you want to use a type alias instead of writing down a long type name multiple times, consider using a generic helper method:

    This avoids declaring an empty class.
     
    Mehmet Anıl Çorapcı
    Greenhorn
    Posts: 5
    1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Piet,
    First of all thanks for giving your class to my name I was too focus to collect list and you showed me TreeMap is better option. I loved your result.lastEntry() trick <3  I agree Stephan's mentions about your helper class naming conventions. Also i think your helper class is confusing, i want to see TreeMap<Integer, List<Mehmet>>  instead of another class. I was tought writing lambda expressions in method's param's  is better but my lambda goes for too long. I am on your side now

    Hi Stephan,
    Your suggestions cool about Piet's helper class naming conventions. Accumulation class seems complicated to me but i will give a shot when i need to declare lamda more than one.
     
    Greenhorn
    Posts: 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Piet,

    I am new here but I know a web site that you can be helped a lot with this subject and other ones.
    Using stream and reduce will be much easier.

    web site -> https://www.techiedelight.com/find-maximum-minimum-custom-objects-java/#:~:text=1.,maximum%20object%20in%20the%20stream



     
    Campbell Ritchie
    Marshal
    Posts: 80613
    467
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Welcome to the Ranch

    That looks a good website.
    But the hard part is defining what more than or less than; once you have that, the Streams interface can find the maximum and minimum very easily.
     
    reply
      Bookmark Topic Watch Topic
    • New Topic