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
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With