Tengo el siguiente código:
list.sort(Comparator .comparing(ProgrammData::getEnd) .thenComparing(ProgrammData::getStart).reversed());
Mi problema es que quiero tener mi lista ordenada por varias cosas: 1.) Agruparlos en eventos futuros y eventos pasados (verificando si System.currentMilliseconds() es más grande que la marca de tiempo final) 2.) Ordenar eventos futuros por empezar ascendiendo 3.) Ordenar eventos pasados por fin descendiendo
¿Puedo hacer esto con Java 8 Lambda o necesito otra forma de clasificar los elementos?
Ejemplo:
events could look like this: name, start, end event1, 2022-02-220100, 2022-02-220300 event2, 2022-02-220200, 2022-02-241800 event3, 2022-02-251200, 2022-02-281500 event4, 2022-02-261600, 2022-02-262100 if now() is 2022-02-221200 So the order should be: event3 (next item in the future) event4 (2nd next item in the future) event2 (Ended closer to now than event1) event1 (Longest in the past)
Prueba esto :
final long currentTime = System.currentTimeMillis(); list.sort((el1, el2) -> { if (el1.equals(el2)) { return 0; } boolean isEl1Future = el1.getEnd().getTime() > currentTime; boolean isEl2Future = el2.getEnd().getTime() > currentTime; if (isEl1Future != isEl2Future) { return isEl1Future ? -1 : 1; } if (Boolean.TRUE.equals(isEl1Future)) { return el1.getStart().before(el2.getStart()) ? -1 : 1; } return el1.getEnd().after(el2.getEnd()) ? -1 : 1; });
Hay varias cosas para notar. Primero, uno es el .thenComparing(...)
, que solo tiene lugar si los resultados de la comparación anterior son iguales. Puede leer más sobre su comportamiento en los documentos .
En segundo lugar, si yo fuera usted, no me molestaría en abusar del flujo si pudiera resolverlo con un simple comparador. Suponiendo que está buscando una nueva instancia de la lista ProgrammData
, escribí mi código en estilo de transmisión, pero el Comparator se puede usar con el método de sort
de List
.
private List<ProgrammData> sortedProgramms(List<ProgrammData> dataList) { final LocalDateTime now = LocalDateTime.now(); return dataList.stream() .sorted((e1, e2) -> { if (e1.getStart().isAfter(now) && e2.getStart().isAfter(now)) { return e1.getStart().compareTo(e2.getStart()); } return e2.getEnd().compareTo(e1.getEnd()); }) .collect(Collectors.toList()); }
LocalDateTime().now() está usando System.currentTimeMillis() adentro, si no hay un reloj dado más preciso.
Debe dividir los eventos pasados y futuros en diferentes listas y ordenarlos en consecuencia. El paso final es unirse a ambas listas.
public static void main(String[] args) { ProgrammData programmData1 = new ProgrammData("a", LocalDateTime.now().plusDays(1), LocalDateTime.now().plusDays(1)); ProgrammData programmData2 = new ProgrammData("b", LocalDateTime.now().plusDays(2), LocalDateTime.now().plusDays(2)); ProgrammData programmData3 = new ProgrammData("c", LocalDateTime.now().minusDays(1), LocalDateTime.now().minusDays(1)); ProgrammData programmData4 = new ProgrammData("c", LocalDateTime.now().minusDays(2), LocalDateTime.now().minusDays(2)); List<ProgrammData> programmDataList = new ArrayList<>(); programmDataList.add(programmData1); programmDataList.add(programmData2); programmDataList.add(programmData3); programmDataList.add(programmData4); final List<ProgrammData> collect = programmDataList.stream().sorted(Comparator .comparing(ProgrammData::end)).toList(); LocalDateTime localDateTime = LocalDateTime.now(); final List<ProgrammData> pastEvents = collect.stream().filter(pd -> pd.end.isBefore(localDateTime)) .sorted(Comparator .comparing(ProgrammData::end).reversed()).toList(); final List<ProgrammData> futureEvents = collect.stream().filter(pd -> pd.end.isAfter(localDateTime)).toList(); List<ProgrammData> sortedListAsRequired = new ArrayList<>(); sortedListAsRequired.addAll(futureEvents); sortedListAsRequired.addAll(pastEvents); System.out.println(sortedListAsRequired); } static record ProgrammData(String name, LocalDateTime start, LocalDateTime end) { }
El resultado es algo como esto:
[ProgrammData[name=a, start=2022-02-23T18:08:59.564300200, end=2022-02-23T18:08:59.568806900], ProgrammData[name=b, start=2022-02-24T18:08:59.568806900, end=2022-02-24T18:08:59.568806900], ProgrammData[name=c, start=2022-02-21T18:08:59.568806900, end=2022-02-21T18:08:59.568806900], ProgrammData[name=c, start=2022-02-20T18:08:59.568806900, end=2022-02-20T18:08:59.568806900]]
Tu ejemplo es confuso. Como indica en el encabezado, event2
debe manejarse como si fuera en el futuro, debido a que su hora de finalización ( 2022-02-241800
) es posterior a ahora ( 2022-02-221200
), por lo que los elementos ordenados deben ser
event2 event3 event4 event1
Si eso es correcto, podría intentar algo como lo siguiente:
events.sort((e1, e2) -> { // -1: e1 and e2 in the past // 0: e1 and e2 in distinct periods // +1: e1 and e2 in the future int period = Integer.signum( Integer.signum(e1.getEnd().compareTo(now)) + Integer.signum(e2.getEnd().compareTo(now)) ); if (period == 0) { return -e1.getEnd().compareTo(now); } // > 0: e1 is after e2 // = 0: e1 is equal to e2 // < 0: e1 is before e2 int comparation = e1.getComparingDateTime(now).compareTo( e2.getComparingDateTime(now) ); return period * comparation; });
Dado
class ProgramData { ... public LocalDateTime getComparingDateTime(LocalDateTime reference) { if (reference.isAfter(end)) { // Past return end; } // Future return start; } ... }