Объект OrderEntry:
@Data
public static class OrderEntry {
private String entryNumber;
// giftFlag=0 means the orderEntry is a normal entry
// giftFlag=1 means the orderEntry is a gift entry
private Integer giftFlag;
private List<String> sourceEntryNumbers;
}
GiftFlag=0 означает, что orderEntry является обычной записью.
GiftFlag=1 означает, что orderEntry является записью о подарке.
У меня есть список orderEntry, он содержит обычную запись и запись подарка. Теперь я хочу отсортировать список orderEntry с указанным порядком, сначала обычную запись, если в этой обычной записи есть запись подарка, то во вторую очередь запись подарка.
обновлять: Я хочу отсортировать не-подарки по номеру записи и отслеживать подарки.
Это не сортировка по нескольким полям, и в ней нельзя использовать методы Comparator compare
и thenComparing
.
Как отсортировать этот список? Любая помощь?
@Test
public void testSort() {
OrderEntry orderEntry1 = new OrderEntry();
orderEntry1.setEntryNumber("1");
orderEntry1.setGiftFlag(0);
OrderEntry orderEntry2 = new OrderEntry();
orderEntry2.setEntryNumber("2");
orderEntry2.setGiftFlag(0);
OrderEntry orderEntry3 = new OrderEntry();
orderEntry3.setGiftFlag(1);
// it means this gift orderEntry created from orderEntry1 and orderEntry2
orderEntry3.setSourceEntryNumbers(Arrays.asList("1", "2"));
OrderEntry orderEntry4 = new OrderEntry();
orderEntry4.setEntryNumber("3");
orderEntry4.setGiftFlag(0);
OrderEntry orderEntry5 = new OrderEntry();
orderEntry5.setGiftFlag(1);
// it means this gift orderEntry created from orderEntry3
orderEntry5.setSourceEntryNumbers(Arrays.asList("3"));
OrderEntry orderEntry6 = new OrderEntry();
orderEntry6.setEntryNumber("4");
orderEntry6.setGiftFlag(0);
OrderEntry orderEntry7 = new OrderEntry();
orderEntry7.setGiftFlag(1);
// it means this gift orderEntry created from orderEntry3
orderEntry7.setSourceEntryNumbers(Arrays.asList("4"));
OrderEntry orderEntry8 = new OrderEntry();
orderEntry8.setEntryNumber("8");
orderEntry8.setGiftFlag(0);
List<OrderEntry> list = new ArrayList<>();
list.add(orderEntry1);
list.add(orderEntry2);
list.add(orderEntry4);
list.add(orderEntry6);
list.add(orderEntry3);
list.add(orderEntry5);
list.add(orderEntry7);
list.add(orderEntry8);
System.out.println(JSON.toJSONString(list));
// output:
// [{"entryNumber":"1","giftFlag":0},{"entryNumber":"2","giftFlag":0},{"entryNumber":"3","giftFlag":0},{"entryNumber":"4","giftFlag":0},{"giftFlag":1,"sourceEntryNumbers":["1","2"]},{"giftFlag":1,"sourceEntryNumbers":["3"]},{"giftFlag":1,"sourceEntryNumbers":["4"]},{"entryNumber":"8","giftFlag":0}]
// expected output:
// [{"entryNumber":"1","giftFlag":0},{"entryNumber":"2","giftFlag":0},{"giftFlag":1,"sourceEntryNumbers":["1","2"]},{"entryNumber":"3","giftFlag":0},{"giftFlag":1,"sourceEntryNumbers":["3"]},{"entryNumber":"4","giftFlag":0},{"giftFlag":1,"sourceEntryNumbers":["4"]},{"entryNumber":"8","giftFlag":0}]
}
В объекте списка есть обычная запись и запись о подарке, но запись о подарке имеет дополнительное свойство sourceEntryNumbers
, это означает, что запись о подарке создана из обычной записи. Например, купи один, получи один бесплатно.
И я хочу отсортировать список с обычным порядком ввода и порядком ввода подарков. Исходный список, например: NormalEntry1, NormalEntry2, NormalEntry3, GiftEntry1, GiftEntry3, и список ожидаемых заказов, например: NormalEntry1, GiftEntry1, NormalEntry2, NormalEntry3, GiftEntry3.....
Ваша проблема в том, что вы не хотите сортировать их, просто сравнивая их попарно, а упорядочивая заказы без подарков по номеру записи и отслеживая подарки. Но я все еще не понимаю ваш пример в посте. Вы ожидаете, что orderEntry3 появится после orderEntry1 и orderEntry2.
Хотите ли вы поставить подарки в очередь сразу после самой часто упоминаемой обычной записи?
Этот вопрос ненамного лучше вашей оригинальной попытки.
@ValerijDobler Да, заказывая заказы без подарков по номеру записи и отслеживая подарки.
@Holinc, посмотри мой ответ. Достигает ли это того, что вы ищете?
Вы говорите, что не можете использовать comparing
и thenComparing
, но можете. Предоставляемая вами функция не обязательно должна быть ссылкой на метод.
Предполагая, что giftFlag
не имеет значения NULL и entryNumber
не имеет значения NULL для записей о подарках:
Comparator<OrderEntry> entryComparator = Comparator.comparing(OrderEntry::getGiftFlag)
.thenComparing(entry -> entry.getGiftFlag() == 1 ? entry.getEntryNumber() : "");
Это позволит обычным записям предшествовать записям о подарках. Каждая обычная запись получит тот же результат для второго сравнения, и это нормально, если вы не начнете использовать TreeSet
. В результате обычные записи идут первыми в исходном порядке, а за ними следуют подарочные записи, упорядоченные по номеру записи.
Альтернативно можно использовать обычный компаратор:
Comparator<OrderEntry> entryComparator = (entry1, entry2) -> {
int result = entry1.getGiftFlag().compareTo(entry2.getGiftFlag());
if (result == 0 && entry1.getGiftFlag() == 1) {
// entry2.getGiftFlag() == 1 as well
result = entry1.getEntryNumber().compareTo(entry2.getEntryNumber());
}
// else both have getGiftFlag() == 0, or they have different gift flags
return result;
}
Несвязанный совет: используйте перечисление для giftFlag
. GiftFlag.NORMAL
понятнее, чем 0
.
public enum GiftFlag {
NORMAL,
GIFT,
}
В объекте списка есть обычная запись и запись о подарке, но запись о подарке имеет дополнительное свойство sourceEntryNumbers, это означает, что запись о подарке создана из обычной записи. Например, купите один, получите один бесплатно. И я хочу отсортировать список с обычным порядком ввода и порядком ввода подарков. Исходный список, например: normalEntry1, normalEntry2, normalEntry3, giftEntry1, giftEntry3
, и список ожидаемых заказов, например: normalEntry1, giftEntry1, normalEntry2, normalEntry3, giftEntry3
.....
В моем случае это не работает.
Вы можете добавить функцию CompareTo в свой класс OrderEntry.
public static class OrderEntry implements Comparable<OrderEntry> {
private String entryNumber;
// giftFlag=0 means the orderEntry is a normal entry
// giftFlag=1 means the orderEntry is a gift entry
private Integer giftFlag;
private List<String> sourceEntryNumbers;
@Override
public int compareTo(OrderEntry other) {
return Integer.compare(this.giftFlag, other.giftFlag);
}
}
@Test
public void testSort() {
...
Collections.sort(list);
System.out.println(JSON.toJSONString(list));
}
Это не то, чего я хочу.
Если я вас правильно понял, вы хотите, чтобы gift orders
следовал за самым высоким normal orders
, на который они ссылаются.
Затем мы можем добавить метод, возвращающий номер записи или последнюю запись источника, и использовать его в методе сравнения. Также нам нужно выполнить сортировку по GiftFlag, потому что мы хотим, чтобы номер записи «2» располагался перед исходным списком EntryNumbers List.of («1», «2).
@Data
public class OrderEntry implements Comparable<OrderEntry>{
private String entryNumber;
// giftFlag=0 means the orderEntry is a normal entry
// giftFlag=1 means the orderEntry is a gift entry
private Integer giftFlag;
private List<String> sourceEntryNumbers;
// can be omitted, it you know that the sourceEntryNumbers are sorted already
public void setSourceEntryNumbers(List<String> sourceEntryNumbers) {
this.sourceEntryNumbers = sourceEntryNumbers.stream().sorted().toList();
}
private String getEntryNumberForSorting() {
if (entryNumber != null)
//if (giftFlag == 1) // alternatively
{
return entryNumber;
}
//return sourceEntryNumbers.getLast(); // since java 21
return sourceEntryNumbers.get(sourceEntryNumbers.size() - 1);
}
@Override
public int compareTo(OrderEntry o) {
return Comparator.comparing(OrderEntry::getEntryNumberForSorting)
.thenComparing(OrderEntry::getGiftFlag)
.compare(this, o);
}
}
и затем вы можете отсортировать их, например. нравиться
final var orderedOrders = orders.stream()
.sorted()
.toList();
Элегантный способ решить мою проблему. Я публикую свой ответ, добавляя поле sortIndex для его решения. Не могли бы вы помочь мне посмотреть, все работает хорошо?
Как я уже упоминал ниже вашего ответа, это не сработает. Иногда заказ на подарок сортировался в другое место, чем вы упомянули в вопросе, о котором вы хотели бы.
Я пробую свой путь, как показано ниже. Добавляем поле sortIndex
для сортировки.
@Test
public void testSort() {
OrderEntry orderEntry1 = new OrderEntry();
orderEntry1.setEntryNumber("1");
orderEntry1.setGiftFlag(0);
OrderEntry orderEntry2 = new OrderEntry();
orderEntry2.setEntryNumber("2");
orderEntry2.setGiftFlag(0);
OrderEntry orderEntry3 = new OrderEntry();
orderEntry3.setGiftFlag(1);
// it means this gift orderEntry created from orderEntry1 and orderEntry2
orderEntry3.setSourceEntryNumbers(Arrays.asList("1", "2"));
OrderEntry orderEntry4 = new OrderEntry();
orderEntry4.setEntryNumber("3");
orderEntry4.setGiftFlag(0);
OrderEntry orderEntry5 = new OrderEntry();
orderEntry5.setGiftFlag(1);
// it means this gift orderEntry created from orderEntry3
orderEntry5.setSourceEntryNumbers(Arrays.asList("3"));
OrderEntry orderEntry6 = new OrderEntry();
orderEntry6.setEntryNumber("4");
orderEntry6.setGiftFlag(0);
OrderEntry orderEntry7 = new OrderEntry();
orderEntry7.setGiftFlag(1);
// it means this gift orderEntry created from orderEntry3
orderEntry7.setSourceEntryNumbers(Arrays.asList("4"));
OrderEntry orderEntry8 = new OrderEntry();
orderEntry8.setEntryNumber("8");
orderEntry8.setGiftFlag(0);
List<OrderEntry> list = new ArrayList<>();
list.add(orderEntry1);
list.add(orderEntry2);
list.add(orderEntry4);
list.add(orderEntry6);
list.add(orderEntry3);
list.add(orderEntry5);
list.add(orderEntry7);
list.add(orderEntry8);
System.out.println(JSON.toJSONString(list));
// setting value into sortIndex field
list.forEach(item -> {
if (CollectionUtils.isNotEmpty(item.getSourceEntryNumbers())) {
List<String> sourceEntryNumbers = item.getSourceEntryNumbers().stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
item.setSortIndex(sourceEntryNumbers.get(0));
} else {
item.setSortIndex(item.getEntryNumber());
}
});
// sorting by sortIndex field again
List<OrderEntry> result = list.stream().sorted(Comparator.comparing(OrderEntry::getSortIndex)).collect(Collectors.toList());
// output result
System.out.println(JSON.toJSONString(result));
}
@Data
public static class OrderEntry {
private String entryNumber;
private Integer giftFlag;
private List<String> sourceEntryNumbers;
// add sortIndex field to sort
private String sortIndex;
}
Если вы выберете sourceEntryNumbers.get(0) в качестве индекса, вы будете сортировать orderEntry3 до или после orderEntry2, что также неоптимально.
Должно сработать, я уже отсортировал sourceEntryNumbers с помощью Comparator.reverseOrder() List<String> sourceEntryNumbers = item.getSourceEntryNumbers().stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
В данном случае это сработало случайно. Просто попробуйте сделать это с обратным упорядоченным списком: orderEntry8,orderEntry7,orderEntry6,orderEntry5,orderEntry4,orderEntry3,orderEntry2,orderEntry1
, тогда вы увидите, что под индексом 1 будет orderEntry3
, хотя вы ожидаете, что за orderEntry2
следует orderEntry3, а не наоборот.
Вот почему вам нужна часть .thenComparing(OrderEntry::getGiftFlag)
.
«и не может использовать методы сравнения и сравнения компаратора» - почему бы и нет? Они здесь именно для этого.