Java 8 lambda filtering based on condition as well as order











up vote
12
down vote

favorite
2












I was trying to filter a list based on multiple conditions, sorting.



class Student{
private int Age;
private String className;
private String Name;

public Student(int age, String className, String name) {
Age = age;
this.className = className;
Name = name;
}

public int getAge() {
return Age;
}

public void setAge(int age) {
Age = age;
}

public String getClassName() {
return className;
}

public void setClassName(String className) {
this.className = className;
}

public String getName() {
return Name;
}

public void setName(String name) {
Name = name;
}
}


Now if I have a list of that, say



List<Student> students = new ArrayList<>();
students.add(new Student(24, "A", "Smith"));
students.add(new Student(24, "A", "John"));
students.add(new Student(30, "A", "John"));
students.add(new Student(20, "B", "John"));
students.add(new Student(24, "B", "Prince"));


How would I be able to get a list of the oldest students with a distinct name?
In C# this would be quite simple by using System.Linq GroupBy then comparing and then flattening with select, I'm not too sure how I could achieve the same in Java.










share|improve this question


















  • 7




    students.stream().collect(groupingBy(...)).
    – Andy Turner
    yesterday










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    yesterday










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    yesterday

















up vote
12
down vote

favorite
2












I was trying to filter a list based on multiple conditions, sorting.



class Student{
private int Age;
private String className;
private String Name;

public Student(int age, String className, String name) {
Age = age;
this.className = className;
Name = name;
}

public int getAge() {
return Age;
}

public void setAge(int age) {
Age = age;
}

public String getClassName() {
return className;
}

public void setClassName(String className) {
this.className = className;
}

public String getName() {
return Name;
}

public void setName(String name) {
Name = name;
}
}


Now if I have a list of that, say



List<Student> students = new ArrayList<>();
students.add(new Student(24, "A", "Smith"));
students.add(new Student(24, "A", "John"));
students.add(new Student(30, "A", "John"));
students.add(new Student(20, "B", "John"));
students.add(new Student(24, "B", "Prince"));


How would I be able to get a list of the oldest students with a distinct name?
In C# this would be quite simple by using System.Linq GroupBy then comparing and then flattening with select, I'm not too sure how I could achieve the same in Java.










share|improve this question


















  • 7




    students.stream().collect(groupingBy(...)).
    – Andy Turner
    yesterday










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    yesterday










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    yesterday















up vote
12
down vote

favorite
2









up vote
12
down vote

favorite
2






2





I was trying to filter a list based on multiple conditions, sorting.



class Student{
private int Age;
private String className;
private String Name;

public Student(int age, String className, String name) {
Age = age;
this.className = className;
Name = name;
}

public int getAge() {
return Age;
}

public void setAge(int age) {
Age = age;
}

public String getClassName() {
return className;
}

public void setClassName(String className) {
this.className = className;
}

public String getName() {
return Name;
}

public void setName(String name) {
Name = name;
}
}


Now if I have a list of that, say



List<Student> students = new ArrayList<>();
students.add(new Student(24, "A", "Smith"));
students.add(new Student(24, "A", "John"));
students.add(new Student(30, "A", "John"));
students.add(new Student(20, "B", "John"));
students.add(new Student(24, "B", "Prince"));


How would I be able to get a list of the oldest students with a distinct name?
In C# this would be quite simple by using System.Linq GroupBy then comparing and then flattening with select, I'm not too sure how I could achieve the same in Java.










share|improve this question













I was trying to filter a list based on multiple conditions, sorting.



class Student{
private int Age;
private String className;
private String Name;

public Student(int age, String className, String name) {
Age = age;
this.className = className;
Name = name;
}

public int getAge() {
return Age;
}

public void setAge(int age) {
Age = age;
}

public String getClassName() {
return className;
}

public void setClassName(String className) {
this.className = className;
}

public String getName() {
return Name;
}

public void setName(String name) {
Name = name;
}
}


Now if I have a list of that, say



List<Student> students = new ArrayList<>();
students.add(new Student(24, "A", "Smith"));
students.add(new Student(24, "A", "John"));
students.add(new Student(30, "A", "John"));
students.add(new Student(20, "B", "John"));
students.add(new Student(24, "B", "Prince"));


How would I be able to get a list of the oldest students with a distinct name?
In C# this would be quite simple by using System.Linq GroupBy then comparing and then flattening with select, I'm not too sure how I could achieve the same in Java.







java lambda java-8 java-stream






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked yesterday









The 0bserver

15710




15710








  • 7




    students.stream().collect(groupingBy(...)).
    – Andy Turner
    yesterday










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    yesterday










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    yesterday
















  • 7




    students.stream().collect(groupingBy(...)).
    – Andy Turner
    yesterday










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    yesterday










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    yesterday










7




7




students.stream().collect(groupingBy(...)).
– Andy Turner
yesterday




students.stream().collect(groupingBy(...)).
– Andy Turner
yesterday












Do you only want a list of the oldest and only the oldest ones?
– michaeak
yesterday




Do you only want a list of the oldest and only the oldest ones?
– michaeak
yesterday












Please tell what is the desired result. I.e. How the map/list/whatever looks like.
– michaeak
yesterday






Please tell what is the desired result. I.e. How the map/list/whatever looks like.
– michaeak
yesterday














4 Answers
4






active

oldest

votes

















up vote
13
down vote













Use the toMap collector:



Collection<Student> values = students.stream()
.collect(toMap(Student::getName,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
.values();


Explanation



We're using this overload of toMap:



toMap​(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)




  • Student::getName above is the keyMapper function used to extract the values for the map keys.


  • Function.identity() above is the valueMapper function used to extract the values for the map values where Function.identity() simply returns the elements in the source them selves i.e. the Student objects.


  • BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) above is the merge function used to "decide which Student object to return in the case of a key collission i.e. when two given students have the same name" in this case taking the oldest Student .

  • Finally, invoking values() returns us a collection of students.


The equivalent C# code being:



var values = students.GroupBy(s => s.Name, v => v,
(a, b) => b.OrderByDescending(e => e.Age).Take(1))
.SelectMany(x => x);


Explanation (for those unfamiliar with .NET)



We're using this extension method of GroupBy:



System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult> 
(this System.Collections.Generic.IEnumerable<TSource> source,
Func<TSource,TKey> keySelector,
Func<TSource,TElement> elementSelector,
Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);




  • s => s.Name above is the keySelector function used to extract the value to group by.


  • v => v above is the elementSelector function used to extract the values i.e. the Student objects them selves.


  • b.OrderByDescending(e => e.Age).Take(1) above is the resultSelector which given an IEnumerable<Student> represented as b takes the oldest student.

  • Finally, we apply .SelectMany(x => x); to collapse the resulting IEnumerable<IEnumerable<Student>> into a IEnumerable<Student>.






share|improve this answer























  • Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
    – Luis G.
    yesterday


















up vote
4
down vote













Or without streams:



Map<String, Student> map = new HashMap<>();
students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV));
Collection<Student> max = map.values();





share|improve this answer























  • Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
    – nullpointer
    yesterday






  • 3




    @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
    – Federico Peralta Schaffner
    yesterday




















up vote
1
down vote













If you need a grouping only sorted, it is quite simple:



Map<String, List<Student>> collect = students.stream() // stream capabilities
.sorted(Comparator.comparingInt(Student::getAge).reversed()) // sort by age, descending
.collect(Collectors.groupingBy(Student::getName)); // group by name.


Output in collect:




  • Prince=[Student [Age=24, className=B, Name=Prince]],

  • Smith=[Student [Age=24, className=A, Name=Smith]],

  • John=[Student [Age=30, className=A, Name=John], Student [Age=24, className=A, Name=John], Student [Age=20, className=B, Name=John]]






share|improve this answer






























    up vote
    1
    down vote













    Just to mix and merge the other solutions, you could alternatively do :



    Map<String, Student> nameToStudentMap = new HashMap<>();
    Set<Student> finalListOfStudents = students.stream()
    .map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b))
    .collect(Collectors.toSet());





    share|improve this answer



















    • 3




      This violates the requirement of statelessness on the parameter of Stream.map.
      – Andy Turner
      yesterday













    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',
    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%2f53635022%2fjava-8-lambda-filtering-based-on-condition-as-well-as-order%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    13
    down vote













    Use the toMap collector:



    Collection<Student> values = students.stream()
    .collect(toMap(Student::getName,
    Function.identity(),
    BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
    .values();


    Explanation



    We're using this overload of toMap:



    toMap​(Function<? super T,? extends K> keyMapper,
    Function<? super T,? extends U> valueMapper,
    BinaryOperator<U> mergeFunction)




    • Student::getName above is the keyMapper function used to extract the values for the map keys.


    • Function.identity() above is the valueMapper function used to extract the values for the map values where Function.identity() simply returns the elements in the source them selves i.e. the Student objects.


    • BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) above is the merge function used to "decide which Student object to return in the case of a key collission i.e. when two given students have the same name" in this case taking the oldest Student .

    • Finally, invoking values() returns us a collection of students.


    The equivalent C# code being:



    var values = students.GroupBy(s => s.Name, v => v,
    (a, b) => b.OrderByDescending(e => e.Age).Take(1))
    .SelectMany(x => x);


    Explanation (for those unfamiliar with .NET)



    We're using this extension method of GroupBy:



    System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult> 
    (this System.Collections.Generic.IEnumerable<TSource> source,
    Func<TSource,TKey> keySelector,
    Func<TSource,TElement> elementSelector,
    Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);




    • s => s.Name above is the keySelector function used to extract the value to group by.


    • v => v above is the elementSelector function used to extract the values i.e. the Student objects them selves.


    • b.OrderByDescending(e => e.Age).Take(1) above is the resultSelector which given an IEnumerable<Student> represented as b takes the oldest student.

    • Finally, we apply .SelectMany(x => x); to collapse the resulting IEnumerable<IEnumerable<Student>> into a IEnumerable<Student>.






    share|improve this answer























    • Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
      – Luis G.
      yesterday















    up vote
    13
    down vote













    Use the toMap collector:



    Collection<Student> values = students.stream()
    .collect(toMap(Student::getName,
    Function.identity(),
    BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
    .values();


    Explanation



    We're using this overload of toMap:



    toMap​(Function<? super T,? extends K> keyMapper,
    Function<? super T,? extends U> valueMapper,
    BinaryOperator<U> mergeFunction)




    • Student::getName above is the keyMapper function used to extract the values for the map keys.


    • Function.identity() above is the valueMapper function used to extract the values for the map values where Function.identity() simply returns the elements in the source them selves i.e. the Student objects.


    • BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) above is the merge function used to "decide which Student object to return in the case of a key collission i.e. when two given students have the same name" in this case taking the oldest Student .

    • Finally, invoking values() returns us a collection of students.


    The equivalent C# code being:



    var values = students.GroupBy(s => s.Name, v => v,
    (a, b) => b.OrderByDescending(e => e.Age).Take(1))
    .SelectMany(x => x);


    Explanation (for those unfamiliar with .NET)



    We're using this extension method of GroupBy:



    System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult> 
    (this System.Collections.Generic.IEnumerable<TSource> source,
    Func<TSource,TKey> keySelector,
    Func<TSource,TElement> elementSelector,
    Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);




    • s => s.Name above is the keySelector function used to extract the value to group by.


    • v => v above is the elementSelector function used to extract the values i.e. the Student objects them selves.


    • b.OrderByDescending(e => e.Age).Take(1) above is the resultSelector which given an IEnumerable<Student> represented as b takes the oldest student.

    • Finally, we apply .SelectMany(x => x); to collapse the resulting IEnumerable<IEnumerable<Student>> into a IEnumerable<Student>.






    share|improve this answer























    • Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
      – Luis G.
      yesterday













    up vote
    13
    down vote










    up vote
    13
    down vote









    Use the toMap collector:



    Collection<Student> values = students.stream()
    .collect(toMap(Student::getName,
    Function.identity(),
    BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
    .values();


    Explanation



    We're using this overload of toMap:



    toMap​(Function<? super T,? extends K> keyMapper,
    Function<? super T,? extends U> valueMapper,
    BinaryOperator<U> mergeFunction)




    • Student::getName above is the keyMapper function used to extract the values for the map keys.


    • Function.identity() above is the valueMapper function used to extract the values for the map values where Function.identity() simply returns the elements in the source them selves i.e. the Student objects.


    • BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) above is the merge function used to "decide which Student object to return in the case of a key collission i.e. when two given students have the same name" in this case taking the oldest Student .

    • Finally, invoking values() returns us a collection of students.


    The equivalent C# code being:



    var values = students.GroupBy(s => s.Name, v => v,
    (a, b) => b.OrderByDescending(e => e.Age).Take(1))
    .SelectMany(x => x);


    Explanation (for those unfamiliar with .NET)



    We're using this extension method of GroupBy:



    System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult> 
    (this System.Collections.Generic.IEnumerable<TSource> source,
    Func<TSource,TKey> keySelector,
    Func<TSource,TElement> elementSelector,
    Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);




    • s => s.Name above is the keySelector function used to extract the value to group by.


    • v => v above is the elementSelector function used to extract the values i.e. the Student objects them selves.


    • b.OrderByDescending(e => e.Age).Take(1) above is the resultSelector which given an IEnumerable<Student> represented as b takes the oldest student.

    • Finally, we apply .SelectMany(x => x); to collapse the resulting IEnumerable<IEnumerable<Student>> into a IEnumerable<Student>.






    share|improve this answer














    Use the toMap collector:



    Collection<Student> values = students.stream()
    .collect(toMap(Student::getName,
    Function.identity(),
    BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge))))
    .values();


    Explanation



    We're using this overload of toMap:



    toMap​(Function<? super T,? extends K> keyMapper,
    Function<? super T,? extends U> valueMapper,
    BinaryOperator<U> mergeFunction)




    • Student::getName above is the keyMapper function used to extract the values for the map keys.


    • Function.identity() above is the valueMapper function used to extract the values for the map values where Function.identity() simply returns the elements in the source them selves i.e. the Student objects.


    • BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) above is the merge function used to "decide which Student object to return in the case of a key collission i.e. when two given students have the same name" in this case taking the oldest Student .

    • Finally, invoking values() returns us a collection of students.


    The equivalent C# code being:



    var values = students.GroupBy(s => s.Name, v => v,
    (a, b) => b.OrderByDescending(e => e.Age).Take(1))
    .SelectMany(x => x);


    Explanation (for those unfamiliar with .NET)



    We're using this extension method of GroupBy:



    System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult> 
    (this System.Collections.Generic.IEnumerable<TSource> source,
    Func<TSource,TKey> keySelector,
    Func<TSource,TElement> elementSelector,
    Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);




    • s => s.Name above is the keySelector function used to extract the value to group by.


    • v => v above is the elementSelector function used to extract the values i.e. the Student objects them selves.


    • b.OrderByDescending(e => e.Age).Take(1) above is the resultSelector which given an IEnumerable<Student> represented as b takes the oldest student.

    • Finally, we apply .SelectMany(x => x); to collapse the resulting IEnumerable<IEnumerable<Student>> into a IEnumerable<Student>.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    Aomine

    34.3k62859




    34.3k62859












    • Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
      – Luis G.
      yesterday


















    • Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
      – Luis G.
      yesterday
















    Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
    – Luis G.
    yesterday




    Nice answer. Just wanted to say that using v -> v instead of Function.identity() would make the code more similar to the C# equivalent and so easier to compare.
    – Luis G.
    yesterday












    up vote
    4
    down vote













    Or without streams:



    Map<String, Student> map = new HashMap<>();
    students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV));
    Collection<Student> max = map.values();





    share|improve this answer























    • Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
      – nullpointer
      yesterday






    • 3




      @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
      – Federico Peralta Schaffner
      yesterday

















    up vote
    4
    down vote













    Or without streams:



    Map<String, Student> map = new HashMap<>();
    students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV));
    Collection<Student> max = map.values();





    share|improve this answer























    • Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
      – nullpointer
      yesterday






    • 3




      @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
      – Federico Peralta Schaffner
      yesterday















    up vote
    4
    down vote










    up vote
    4
    down vote









    Or without streams:



    Map<String, Student> map = new HashMap<>();
    students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV));
    Collection<Student> max = map.values();





    share|improve this answer














    Or without streams:



    Map<String, Student> map = new HashMap<>();
    students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV));
    Collection<Student> max = map.values();






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered yesterday









    Eugene

    67.2k997160




    67.2k997160












    • Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
      – nullpointer
      yesterday






    • 3




      @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
      – Federico Peralta Schaffner
      yesterday




















    • Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
      – nullpointer
      yesterday






    • 3




      @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
      – Federico Peralta Schaffner
      yesterday


















    Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
    – nullpointer
    yesterday




    Thought of this while starting of from your initial suggestion, but then an additional Map here, but does map.merge save us compared to toMap?
    – nullpointer
    yesterday




    3




    3




    @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
    – Federico Peralta Schaffner
    yesterday






    @nullpointer This should have been my answer (I'm supposedly the without streams guy here), so I feel I can answer your question... Actually, Collectors.toMap uses Map.merge under the hood. It even says so in the docs: mergeFunction - a merge function, used to resolve collisions between values associated with the same key, as supplied to Map.merge(Object, Object, BiFunction).
    – Federico Peralta Schaffner
    yesterday












    up vote
    1
    down vote













    If you need a grouping only sorted, it is quite simple:



    Map<String, List<Student>> collect = students.stream() // stream capabilities
    .sorted(Comparator.comparingInt(Student::getAge).reversed()) // sort by age, descending
    .collect(Collectors.groupingBy(Student::getName)); // group by name.


    Output in collect:




    • Prince=[Student [Age=24, className=B, Name=Prince]],

    • Smith=[Student [Age=24, className=A, Name=Smith]],

    • John=[Student [Age=30, className=A, Name=John], Student [Age=24, className=A, Name=John], Student [Age=20, className=B, Name=John]]






    share|improve this answer



























      up vote
      1
      down vote













      If you need a grouping only sorted, it is quite simple:



      Map<String, List<Student>> collect = students.stream() // stream capabilities
      .sorted(Comparator.comparingInt(Student::getAge).reversed()) // sort by age, descending
      .collect(Collectors.groupingBy(Student::getName)); // group by name.


      Output in collect:




      • Prince=[Student [Age=24, className=B, Name=Prince]],

      • Smith=[Student [Age=24, className=A, Name=Smith]],

      • John=[Student [Age=30, className=A, Name=John], Student [Age=24, className=A, Name=John], Student [Age=20, className=B, Name=John]]






      share|improve this answer

























        up vote
        1
        down vote










        up vote
        1
        down vote









        If you need a grouping only sorted, it is quite simple:



        Map<String, List<Student>> collect = students.stream() // stream capabilities
        .sorted(Comparator.comparingInt(Student::getAge).reversed()) // sort by age, descending
        .collect(Collectors.groupingBy(Student::getName)); // group by name.


        Output in collect:




        • Prince=[Student [Age=24, className=B, Name=Prince]],

        • Smith=[Student [Age=24, className=A, Name=Smith]],

        • John=[Student [Age=30, className=A, Name=John], Student [Age=24, className=A, Name=John], Student [Age=20, className=B, Name=John]]






        share|improve this answer














        If you need a grouping only sorted, it is quite simple:



        Map<String, List<Student>> collect = students.stream() // stream capabilities
        .sorted(Comparator.comparingInt(Student::getAge).reversed()) // sort by age, descending
        .collect(Collectors.groupingBy(Student::getName)); // group by name.


        Output in collect:




        • Prince=[Student [Age=24, className=B, Name=Prince]],

        • Smith=[Student [Age=24, className=A, Name=Smith]],

        • John=[Student [Age=30, className=A, Name=John], Student [Age=24, className=A, Name=John], Student [Age=20, className=B, Name=John]]







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited yesterday

























        answered yesterday









        michaeak

        690315




        690315






















            up vote
            1
            down vote













            Just to mix and merge the other solutions, you could alternatively do :



            Map<String, Student> nameToStudentMap = new HashMap<>();
            Set<Student> finalListOfStudents = students.stream()
            .map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b))
            .collect(Collectors.toSet());





            share|improve this answer



















            • 3




              This violates the requirement of statelessness on the parameter of Stream.map.
              – Andy Turner
              yesterday

















            up vote
            1
            down vote













            Just to mix and merge the other solutions, you could alternatively do :



            Map<String, Student> nameToStudentMap = new HashMap<>();
            Set<Student> finalListOfStudents = students.stream()
            .map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b))
            .collect(Collectors.toSet());





            share|improve this answer



















            • 3




              This violates the requirement of statelessness on the parameter of Stream.map.
              – Andy Turner
              yesterday















            up vote
            1
            down vote










            up vote
            1
            down vote









            Just to mix and merge the other solutions, you could alternatively do :



            Map<String, Student> nameToStudentMap = new HashMap<>();
            Set<Student> finalListOfStudents = students.stream()
            .map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b))
            .collect(Collectors.toSet());





            share|improve this answer














            Just to mix and merge the other solutions, you could alternatively do :



            Map<String, Student> nameToStudentMap = new HashMap<>();
            Set<Student> finalListOfStudents = students.stream()
            .map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b))
            .collect(Collectors.toSet());






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited yesterday

























            answered yesterday









            nullpointer

            37.5k1072145




            37.5k1072145








            • 3




              This violates the requirement of statelessness on the parameter of Stream.map.
              – Andy Turner
              yesterday
















            • 3




              This violates the requirement of statelessness on the parameter of Stream.map.
              – Andy Turner
              yesterday










            3




            3




            This violates the requirement of statelessness on the parameter of Stream.map.
            – Andy Turner
            yesterday






            This violates the requirement of statelessness on the parameter of Stream.map.
            – Andy Turner
            yesterday




















            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.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • 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%2f53635022%2fjava-8-lambda-filtering-based-on-condition-as-well-as-order%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







            Popular posts from this blog

            Morgemoulin

            Scott Moir

            Souastre