Java 8 lambda filtering based on condition as well as order












19














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
    Dec 5 '18 at 14:56










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    Dec 5 '18 at 15:07










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    Dec 5 '18 at 15:38


















19














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
    Dec 5 '18 at 14:56










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    Dec 5 '18 at 15:07










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    Dec 5 '18 at 15:38
















19












19








19


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 Dec 5 '18 at 14:55









The 0bserverThe 0bserver

202110




202110








  • 7




    students.stream().collect(groupingBy(...)).
    – Andy Turner
    Dec 5 '18 at 14:56










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    Dec 5 '18 at 15:07










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    Dec 5 '18 at 15:38
















  • 7




    students.stream().collect(groupingBy(...)).
    – Andy Turner
    Dec 5 '18 at 14:56










  • Do you only want a list of the oldest and only the oldest ones?
    – michaeak
    Dec 5 '18 at 15:07










  • Please tell what is the desired result. I.e. How the map/list/whatever looks like.
    – michaeak
    Dec 5 '18 at 15:38










7




7




students.stream().collect(groupingBy(...)).
– Andy Turner
Dec 5 '18 at 14:56




students.stream().collect(groupingBy(...)).
– Andy Turner
Dec 5 '18 at 14:56












Do you only want a list of the oldest and only the oldest ones?
– michaeak
Dec 5 '18 at 15:07




Do you only want a list of the oldest and only the oldest ones?
– michaeak
Dec 5 '18 at 15:07












Please tell what is the desired result. I.e. How the map/list/whatever looks like.
– michaeak
Dec 5 '18 at 15:38






Please tell what is the desired result. I.e. How the map/list/whatever looks like.
– michaeak
Dec 5 '18 at 15:38














4 Answers
4






active

oldest

votes


















17














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.
    Dec 5 '18 at 17:08



















7














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
    Dec 5 '18 at 15:27






  • 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
    Dec 5 '18 at 15:45





















2














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































    2














    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
      Dec 5 '18 at 22:00













    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%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









    17














    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.
      Dec 5 '18 at 17:08
















    17














    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.
      Dec 5 '18 at 17:08














    17












    17








    17






    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 Dec 5 '18 at 15:37

























    answered Dec 5 '18 at 14:56









    AomineAomine

    41.7k74071




    41.7k74071












    • 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.
      Dec 5 '18 at 17:08


















    • 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.
      Dec 5 '18 at 17:08
















    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.
    Dec 5 '18 at 17:08




    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.
    Dec 5 '18 at 17:08













    7














    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
      Dec 5 '18 at 15:27






    • 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
      Dec 5 '18 at 15:45


















    7














    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
      Dec 5 '18 at 15:27






    • 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
      Dec 5 '18 at 15:45
















    7












    7








    7






    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 Dec 5 '18 at 15:18

























    answered Dec 5 '18 at 15:09









    EugeneEugene

    68.5k999163




    68.5k999163












    • 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
      Dec 5 '18 at 15:27






    • 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
      Dec 5 '18 at 15:45




















    • 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
      Dec 5 '18 at 15:27






    • 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
      Dec 5 '18 at 15:45


















    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
    Dec 5 '18 at 15:27




    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
    Dec 5 '18 at 15:27




    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
    Dec 5 '18 at 15:45






    @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
    Dec 5 '18 at 15:45













    2














    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




























      2














      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


























        2












        2








        2






        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 Dec 5 '18 at 15:45

























        answered Dec 5 '18 at 14:57









        michaeakmichaeak

        749315




        749315























            2














            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
              Dec 5 '18 at 22:00


















            2














            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
              Dec 5 '18 at 22:00
















            2












            2








            2






            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 Dec 5 '18 at 16:17

























            answered Dec 5 '18 at 16:08









            nullpointernullpointer

            44.5k1095183




            44.5k1095183








            • 3




              This violates the requirement of statelessness on the parameter of Stream.map.
              – Andy Turner
              Dec 5 '18 at 22:00
















            • 3




              This violates the requirement of statelessness on the parameter of Stream.map.
              – Andy Turner
              Dec 5 '18 at 22:00










            3




            3




            This violates the requirement of statelessness on the parameter of Stream.map.
            – Andy Turner
            Dec 5 '18 at 22:00






            This violates the requirement of statelessness on the parameter of Stream.map.
            – Andy Turner
            Dec 5 '18 at 22:00




















            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%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

            Sphinx de Gizeh

            Dijon

            Guerrita