Как выполнить итерацию по списку объектов, преобразовать поле, сравнить его, а затем отсортировать по этому полю?

У меня возникла проблема, когда я считаю, что мне нужно объединить несколько концепций, о которых я читаю, но я не могу найти способ их объединения, который имеет смысл или что было бы наиболее эффективным. Вот моя ситуация:

Я работаю с микросервисами, поэтому это так странно специфично. По сути, я получаю список объектов Volume из другого сервиса. Объект Volume содержит три поля: тип String, дату String (которая на самом деле представляет время в формате «ЧЧ: мм», виноваты разработчики моделей данных в соглашениях об именах) и int close.

Что я пытаюсь сделать, так это взять этот список объектов и отсортировать по дате (времени), а затем создать новый список объектов, который будет содержать те же даты (время), но будет иметь разные значения полей на основе расчетов, которые я делает. Я считаю, что для сортировки по времени мне нужно преобразовать поля времени в объекты Date, а затем сравнить их. Я изо всех сил пытаюсь перебирать объекты и сравнивать преобразованные поля. Что-то, что, как мне кажется, поставило меня на правильный путь, это: field">Как отсортировать список‹Объект› по алфавиту, используя поле имени объекта

Но я не могу заставить это работать. Вот мой код:

volumeResources.sort(volumeResources, new Comparator<VolumeResource>(){
        @Override
        public int compare(VolumeResource v1, VolumeResource v2) {
            SimpleDateFormat format = new SimpleDateFormat("HH:mm");
            try {
                Date d1 = format.parse(v1.getDate());
                Date d2 = format.parse(v2.getDate());
            } catch (ParseException e) {
                log.error("Error in parsing string to date. ", e);
            }
            return d1.compareTo(d2);
        }
    });

Теперь сразу же я знаю, что это должно быть неправильно, потому что я начал сравнивать VolumeResources v1 и v2, но вместо этого попытался сравнить даты в конце. Вместо приведенного выше оператора return я также попробовал приведенный ниже, но я не думаю, что он всегда будет работать, потому что на самом деле он не устанавливает форматированный объект в объект Date:

return format.parse(v1.getDate()).compareTo(format.parse(v2.getDate()));

Так вот где я потерялся. Это кажется довольно простой необходимостью, когда она описана в псевдокоде, но я не могу понять, как заставить ее работать функционально. Бонусные баллы, если есть способ, которым я могу легко заполнить другие поля, которые мне нужны, из этого. Двойные бонусные баллы за использование лямбда-выражений или за помощь в повышении эффективности.

Спасибо за любую помощь всем.


person Crislips    schedule 11.07.2017    source источник
comment
В чем точно ваша проблема? Почему ваша программа не выполняется должным образом?   -  person Marvin    schedule 11.07.2017
comment
Это даже компилируется?   -  person assylias    schedule 11.07.2017
comment
@Marvin Эта основная проблема заключается в попытке выяснить, как отсортировать список объектов по строке времени.   -  person Crislips    schedule 11.07.2017


Ответы (2)


Если вы используете Java 8 и выше, сортировка по времени (которая представлена ​​в виде строки) может выглядеть так:

    volumeResources.sort(new Comparator<VolumeResource>() {
        @Override
        public int compare(VolumeResource v1, VolumeResource v2) {
            return v1.getDate().compareTo(v2.getDate());
        }
    });

До Java 8 это должно выглядеть так:

    Collections.sort(volumeResources, new Comparator<VolumeResource>() {
        @Override
        public int compare(VolumeResource v1, VolumeResource v2) {
            return v1.getDate().compareTo(v2.getDate());
        }
    });

Использование лямбды:

    volumeResources.sort((v1, v2) -> v1.getDate().compareTo(v2.getDate()));

Предполагая, что volumeResources является заполненным изменяемым List (не null), и все записи имеют правильно заполненное поле даты с правильно сформированным временем (без пробелов, табуляций или отсутствующих начальных 0)

Пояснение

Согласно вашему определению поля даты, оно естественным образом сортируется как строка, вам не нужно преобразовывать их в класс java Date.

В вашем примере есть проблема с использованием метода Java 8 sort, определенного в интерфейсе List, таким же образом, как это было до Java 8 с использованием служебного класса Collections - это неправильно, вам не нужно указывать коллекцию в качестве первого параметра.

person Vladimir L.    schedule 11.07.2017
comment
Спасибо за помощь в этом. Я упомянул Яношу, что у меня есть еще одно предостережение, до которого я еще не дошел, но собирался изучить его, как только разберусь с этим. Допустим, время идет 23:30, 24:00, 24:30, 01:00, 01:30, 02:00. Это означало бы прохождение полуночи и должно было бы наступить позже. Как я могу объяснить это? - person Crislips; 12.07.2017
comment
@Crislips, можете ли вы привести пример неправильно определенного времени, смешанного с правильно определенным временем, и ваши ожидания, где записи с неправильным временем должны быть помещены в отсортированный список? - person Vladimir L.; 12.07.2017
comment
Если я вас правильно понял, вот что я имею в виду. Мне нужно просмотреть эти времена в порядке появления, а не только по номеру. Итак, скажем, у меня есть ситуация @Vladimir L, когда время пересекает полночь, и время увеличивается по порядку. Мне нужен список объектов, которые будут отсортированы так: 23:30, 24:00, 24:30, 01:00, 01:30, 02:00. Но с текущим кодом они будут отсортированы как: 01:00, 01:30, 02:00, 23:30, 24:00, 24:30: - person Crislips; 12.07.2017
comment
@Crislips Как вы решаете, с какого времени начинать заказ? Что, если запись 01:30 относится к дню с записью 23:30, а не к следующему дню и просто по совпадению была введена после записи с 23:30? Я имею в виду, представьте себе последовательность: 17:50, 01:30, 17:40, 20:30, 23:12, 01:31, 01:30 — как это должно быть отсортировано в конце? - person Vladimir L.; 12.07.2017
comment
Таким образом, числа всегда будут иметь одинаковый интервал между ними. Первое число — это время начала, а последнее число — текущее время. Время появится в равномерном распределении между ними. Таким образом, будет очевидно, если они происходят в течение ночи, потому что они будут увеличиваться по определенной схеме. - person Crislips; 12.07.2017
comment
@Crislips, записи уже отсортированы по времени? если да, то зачем опять их сортировать по времени? ваши требования действительно сбивают с толку, я думаю, может помочь хороший пример данных, близких к реальным, вы можете поделиться им через pastebin.com - person Vladimir L.; 12.07.2017
comment
Поэтому при передаче во внешний интерфейс порядок не имеет значения. Но так как мне нужно заполнять поля объектов в определенное время в порядке возрастания, для меня это имеет значение в бэкенде. Список не всегда может быть предоставлен мне по порядку, поэтому мне нужно убедиться, что он упорядочен, прежде чем я буду работать с ним. Итак, псевдокод, о котором я думаю, будет таким: получить список из другого сервиса --> отсортировать по времени --> заполнить новые объекты нулевым типом и закрыть, но упорядоченное время в новый список --> обновить эти объекты с помощью закрытия выполненные мной расчеты --› вернуть новый список объектов - person Crislips; 12.07.2017

Дата в Java должна иметь год, месяц, день. Но у вас нет таких значений, у вас есть только HH:mm (часы, минуты). Использование дат здесь неуместно. (И называть эти значения "датой" тоже странно, предлагаю переименовать.)

Обратите внимание, что правильно сформированные HH:mm могут быть отсортированы по алфавиту для правильного порядка. Поэтому все, что вам нужно сделать, это убедиться, что время ввода соответствует шаблону \d\d:\d\d. Если вы получили, например, 9:15, добавьте отступ 0 слева. Что-то вроде этого:

volumeResources.sort(volumeResources, new Comparator<VolumeResource>() {
    @Override
    public int compare(VolumeResource v1, VolumeResource v2) {
        return sanitized(v1.getDate()).compareTo(sanitized(v2.getDate());
    }
});

Метод sanitized предназначен для вас, чтобы реализовать его соответствующим образом. Если значения уже имеют правильный формат типа String, вы можете отказаться от этих вызовов и упростить до:

        return v1.getDate().compareTo(v2.getDate();

Использование лямбды:

volumeResources.sort(volumeResources, (v1, v2) -> sanitized(v1.getDate()).compareTo(sanitized(v2.getDate()));
person janos    schedule 11.07.2017
comment
Спасибо за совет. Соглашения о данных не были определены мной, и на самом деле это не стоит битвы с разработчиками моделей данных. Я знаю, что Дата - плохо выбранное имя. Думаю, в этой ситуации я мог бы использовать LocalDateTime вместо этого, но то, что вы написали, определенно чище. У меня есть еще одно предостережение, до которого я еще не дошел, но собирался изучить его, как только разберусь с этим. Допустим, время идет 23:30, 24:00, 24:30, 01:00, 01:30, 02:00. Это означало бы прохождение полуночи и должно было бы наступить позже. Как я могу объяснить это? - person Crislips; 12.07.2017
comment
Насколько я знаю, это предел требований для этого. Я старался быть максимально кратким в своем первоначальном ответе, но совершенно забыл включить это. Но времена должны оставаться такими же, как и в окончательном возвращении. - person Crislips; 12.07.2017
comment
@Crislips Все важные требования должны были быть указаны в вопросе. В идеале с примерами входных данных и ожидаемых результатов, особенно с учетом сложных угловых случаев, с которыми вам нужно справиться. Если вы забыли это сделать, уже поздно что-либо менять после получения ответа. Правильный способ использования этого сайта в этом случае — задать новый вопрос. И не забудьте указать все важные детали в следующий раз. - person janos; 12.07.2017
comment
Это действительно не приходило мне в голову во время первоначального вопроса. Это то, что я понял позже, но я искренне думаю, что это то, что нужно изменить в том, как данные передаются мне из другого сервиса. Это не так надежно, как есть. - person Crislips; 12.07.2017