Оставьте последний объект активным и деактивируйте старых по дате - PullRequest
0 голосов
/ 11 октября 2018

У меня есть 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;
    }
}

(я знаю ... Строка болит глаза).И это пример данных, над которыми я работаю:

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

Я пытаюсь установить все объекты как active = 0 с потоком, кроме самых последних, которые я хочуоставайтесь активными.

Я немного застрял здесь, я не могу найти правильный способ сделать это:

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

Ожидаемый результат должен быть:

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

Спасибо

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Нет необходимости сортировать. Просто найдите максимальный ( недавний ) объект путем сравнения свойства даты.

MyObject recent = Collections.max(list,Comparator.comparing(MyObject::getDate));
list.stream().filter(myObject -> !myObject.equals(recent))
            .forEach(myObject -> myObject.setActive("0"));
0 голосов
/ 11 октября 2018

РЕДАКТИРОВАТЬ: Показанный здесь подход может рассматриваться как злоупотребление операцией Stream.map, хотя на практике она всегда будет работать (с предупреждением о заключительной ноте в конце начальнойверсия сообщения).

Пожалуйста, обратитесь к приложению для более чистого подхода.


Нет необходимости выполнять какую-либо сортировку (которая является операцией O(NlogN)), когда всевам нужно найти элемент с максимальной датой.

Вы можете просмотреть список элементов MyObject, деактивировать их все, найти элемент с максимальной датой и, наконец, активировать его:

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

Этот код читался бы намного лучше, если бы у класса MyObject были бы беглые методы для установки свойства active:

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

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

Теперь решение стало бы:

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

Примечание: этот подход может не работать, если источник потока сообщает о том, что он отсортирован.Поскольку вы используете список, этого не произойдет.


Добавление:

Как обсуждалось в комментариях, самый чистый подход будетчтобы установить все элементы в неактивное состояние, затем найти элемент с максимальной датой и установить его в активное состояние:

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

Или используя беглые методы:

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

Конечно,этот подход требует 2 прохода по списку, но он ясно показывает намерение разработчика и не злоупотребляет потоковым API.

Вариант этого последнего фрагмента может быть:

myList.forEach(MyObject::deactivated);
if (!myList.isEmpty()) 
        Collections.max(myList, Comparator.comparing(MyObject::getDate))
                .activated();
0 голосов
/ 11 октября 2018

Кажется, вам сначала нужно отсортировать в обратном порядке, чтобы интересующий вас элемент стал первым:

myList.stream()
      .sorted(Comparator.comparing(MyObject::getDate, Comparator.reverseOrder()))
      .skip(1)
      .forEach(x -> x.setActive("0"))

, а затем пропустить его, установив для других значение 0.

...