将最后一个对象保持为活动状态,并按日期停用olders

Lev*_*and 4 java java-8 java-stream

我有一个List<MyObject>,有3个属性:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

(我知道......弦伤了眼睛).这是我正在研究的样本数据:

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
Run Code Online (Sandbox Code Playgroud)

我要做的是将所有对象设置为active = 0流,除了最近的,我想保持活动状态.

我有点卡在这里,我无法匹配正确的方法:

myList.stream()
    .sorted(Comparator.comparing(MyObject::getDate))
    //what now?
;
Run Code Online (Sandbox Code Playgroud)

预期产量应为:

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
Run Code Online (Sandbox Code Playgroud)

谢谢

Fed*_*ner 5

编辑:这里显示的方法可能被视为滥用Stream.map操作,尽管在实践中总会(与最后需要说明的在后的最初版本结束的警告)工作.

有关更清洁的方法,请参阅附录.


O(NlogN)当你所要做的就是找到具有最大日期的元素时,没有必要进行任何排序(这是一个操作).

您可以流式传输MyObject元素列表,停用所有元素,然后找到具有最大日期的元素,最后激活它:

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

如果MyObject类具有设置active属性的流畅方法,则此代码将更好地读取:

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

public MyObject deactivated() {
    active = "0";
    return this;
}
Run Code Online (Sandbox Code Playgroud)

现在解决方案将成为:

myList.stream()
    .map(MyObject::deactivated)
    .max(Comparator.comparing(MyObject::getDate))
    .ifPresent(MyObject::activated);
Run Code Online (Sandbox Code Playgroud)

注意:如果流的源将自身报告为已排序,则此方法可能不起作用.当您使用列表时,这不会发生.


附录:

正如评论中所讨论的,最干净的方法是将所有元素设置为非活动状态,然后找到具有最大日期的元素并将其设置为活动状态:

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

或者使用流利的方法:

myList.forEach(MyObject::deactivated);
myList.stream()
    .max(Comparator.comparing(MyObject::getDate))
    .ifPresent(MyObject::activated);
Run Code Online (Sandbox Code Playgroud)

当然,这种方法需要在列表上进行2次传递,但它清楚地显示了开发人员的意图,并且不会滥用流API.

最后一个片段的变体可能是:

myList.forEach(MyObject::deactivated);
if (!myList.isEmpty()) 
        Collections.max(myList, Comparator.comparing(MyObject::getDate))
                .activated();
Run Code Online (Sandbox Code Playgroud)

  • 你和尤金的答案都很好,但我认为这更好.感谢非常明确的解释 (2认同)