Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep last object as active and deactivate the olders by date

I have a List<MyObject> , with 3 properties:

public class MyObject{
    long id;
    String active; 
    java.util.Date date;

    public MyObject(long id, String active, Date date) {
        this.id = id;
        this.active = active;
        this.date = date;
    }
}

(I know ... String hurts eyes). And this is a sample data which I'm working on:

ID  | ACTIVE | DATE
500925  1   2017-12-01 11:43:34
501145  1   2018-10-11 11:41:14
501146  1   2018-10-11 11:42:51
501147  1   2018-10-11 11:45:37

What I'm trying to do is setting all objects as active = 0 with a stream, except for the most recent , which I wanna keep as active.

I'm a bit stuck here, I can't match the correct way to do this:

myList.stream()
    .sorted(Comparator.comparing(MyObject::getDate))
    //what now?
;

The expected output should be:

ID  | ACTIVE | DATE
500925  0   2017-12-01 11:43:34
501145  0   2018-10-11 11:41:14
501146  0   2018-10-11 11:42:51
501147  1   2018-10-11 11:45:37

Thanks

like image 572
Leviand Avatar asked Jan 28 '23 08:01

Leviand


1 Answers

EDIT: The approach shown here might be seen as an abuse of the Stream.map operation, even though in practice it will always work (with the caveat of the final note at the end of the initial version of the post).

Please refer to the addendum for a cleaner approach.


It's not necessary to do any sorting (which is a O(NlogN) operation), when all you have to do is find the element with the max date.

You could stream the list of MyObject elements, deactivate all of them, then find the element with the max date and finally activate it:

myList.stream()
    .map(myObject -> { myObject.setActive("0"); return myObject; })
    .max(Comparator.comparing(MyObject::getDate))
    .ifPresent(myObject -> myObject.setActive("1"));

This code would read much better if the MyObject class would have fluent methods to set the active property:

public MyObject activated() {
    active = "1";
    return this;
}

public MyObject deactivated() {
    active = "0";
    return this;
}

Now the solution would become:

myList.stream()
    .map(MyObject::deactivated)
    .max(Comparator.comparing(MyObject::getDate))
    .ifPresent(MyObject::activated);

Note: this approach might not work if the source of the stream reports itself as sorted. As you're using a list, this won't happen.


Addendum:

As discussed in the comments, the cleanest approach would be to set all the elements to inactive, then find the element with the max date and set it to active:

myList.forEach(myObject -> myObject.setActive("0"));
myList.stream()
    .max(Comparator.comparing(MyObject::getDate))
    .ifPresent(myObject -> myObject.setActive("1"));

Or using the fluent methods:

myList.forEach(MyObject::deactivated);
myList.stream()
    .max(Comparator.comparing(MyObject::getDate))
    .ifPresent(MyObject::activated);

Of course, this approach requires 2 passes over the list, but it clearly shows the intention of the developer and doesn't abuse the stream API.

A variant of this last snippet could be:

myList.forEach(MyObject::deactivated);
if (!myList.isEmpty()) 
        Collections.max(myList, Comparator.comparing(MyObject::getDate))
                .activated();
like image 67
fps Avatar answered Jan 31 '23 07:01

fps