Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 lambda filtering based on condition as well as order

Tags:

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.

like image 437
The 0bserver Avatar asked Dec 05 '18 14:12

The 0bserver


People also ask

Can we use multiple filters in Java 8?

Overview However, we'll learn how to use the filter() method with as many condition filters as we require. More filters can be applied in a variety of methods, such using the filter() method twice or supplying another predicate to the Predicate. and() method.

How do you add two conditions to a stream filter?

You can use the firstPredicate. and(secondPredicate) to filter results on multiple conditions. The first predicate receives each element from the stream. If the first predicate evaluates to true, then te second predicate receives the same element.

Can we use multiple filters in stream?

2.1. Multiple Filters. The Stream API allows chaining multiple filters.

Does Java stream filter preserve order?

If you have an ordered stream and perform operations which guarantee to maintain the order, it doesn't matter whether the stream is processed in parallel or sequential; the implementation will maintain the order.

How to sort a collection without lambdas in Java?

2. Basic Sort Without Lambdas Before Java 8, sorting a collection would involve creating an anonymous inner class for the Comparator used in the sort: 3. Basic Sort With Lambda Support With the introduction of Lambdas, we can now bypass the anonymous inner class and achieve the same result with simple, functional semantics:

How to apply the if-else condition in Java 8 stream filter?

The if-else condition can be applied using the lambda expressions in stream filter () function. 1. Java 8 stream – if-else logic The 'if-else' condition can be put as a lambda expression in stream.forEach () function in form of a Consumer action.

How to filter Java streams with single condition?

GitHub link is given at the end of the article for the shown examples. 2. Stream.filter () with Single Condition First, We'll start by looking at how to apply the single filter condition to java streams. Predicate is passed as an argument to the filter () method. Each value in the stream is evaluated to this predicate logic.

What are lambda expressions in Java 8?

An example is java.lang.Runnable). lambda expressions implement the only abstract function and therefore implement functional interfaces lambda expressions are added in Java 8 and provide below functionalities.


1 Answers

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>.
like image 60
Ousmane D. Avatar answered Sep 24 '22 19:09

Ousmane D.