Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good way to filter list distincted by property and ordered by date

I have very simple thing to do, i have list of persons like this:

[{
    name: John,
    date: 01-01-2018,
    attend: true
},
{
    name: Adam,
    date: 01-01-2018,
    attend: false
},
{
    name: Adam,
    date: 01-02-2018,
    attend: true
},
{
    name: JOHN,
    date: 01-02-2018,
    attend: false
}]

Result of this array should be: Adam (true), John (false)

So i need to return list of latest entries from users, in this case John first confirmed that he is attending, then he changed his mind and told that he is not attending so i'm returning his last entry (note that sometimes it's written JOHN and sometimes John but it is the same person, that is kind of tricky part)

My question what is best approach to filter out this kind of list, i was thinking applying "unique by property java stream" but first will need to order persons by date descending and names (to upper/lower case) and then i would need somehow to take latest entry.

Anyone have any good idea what is best approach to this ?

like image 596
Sahbaz Avatar asked Dec 05 '18 16:12

Sahbaz


2 Answers

You can use Collectors.toMap to do the same as:

List<Person> finalList = new ArrayList<>(people.stream()
        .collect(Collectors.toMap(a -> a.getName().toLowerCase(),  // name in lowercase as the key of the map (uniqueness)
                Function.identity(), // corresponding Person as value
                (person, person2) -> person.getDate().isAfter(person2.getDate()) ? person : person2)) // merge in case of same name based on which date is after the other
        .values()); // fetch the values

Note: The above assumes the minimal Person class to be

class Person {
    String name;
    java.time.LocalDate date;
    boolean attend;
    // getters and setters
}
like image 183
Naman Avatar answered Nov 18 '22 09:11

Naman


You could use the toMap collector:

Collection<Person> values = source.stream()
                    .collect(toMap(e -> e.getName().toLowerCase(),
                            Function.identity(),
                            BinaryOperator.maxBy(Comparator.comparing(Person::getDate))))
                    .values();

see this answer for an explanation as to how toMap works

like image 4
Ousmane D. Avatar answered Nov 18 '22 09:11

Ousmane D.