Сортировка списка объектов на основе значений, взятых из другого класса

#java #sorting #comparator

#java #сортировка #компаратор

Вопрос:

У меня есть список объектов класса «Категория»:

     public class Category {
    
        private String originalId;
        private Double ordinal;
        private String sportId;
        private String sportName;
        private String type;
        private String version;
}
 

И список объектов класса «League»:

 public class League {

    private String leagueName;
    private String originalId;
    private int rank;

    public League(String name, String originalId, int rank) {
        this.leagueName = name;
        this.originalId = originalId;
        this.rank = rank;
    }
 

Эти классы описывают одни и те же объекты (поэтому значение поля «originalId» класса «Category» равно значению поля «originalId» класса «League»), но значения для них взяты из разных источников, поэтому они были разделены с самого начала

Что мне нужно сделать, так это отсортировать список «Категория» по значению поля «ранг» из класса «Лига»

Итак, логика сортировки должна быть следующей:

  1. Для каждого объекта «Category» я попытаюсь найти соответствующий объект «League», сравнивая их поле «originalId»
  2. если найден соответствующий объект, то возьмите значение поля «ранг» из объекта «Лига» и используйте его для сортировки списка объектов «Категории» по рангу
  3. если соответствующий объект не найден, то такой объект «Категории» должен быть перемещен в конец списка во время сортировки

Итак, компаратор должен быть таким:

 public static Comparator<Category> byRank() {
        return nullsLast(comparing(Category::getRankFromCorrespondingLeagueObject, nullsLast(naturalOrder())));
    }
 

И вот тут я зашел в тупик, потому что для меня необычно использовать значение поля, взятое из другого объекта, для его использования при сортировке

Есть ли какой-нибудь простой хороший подход к этому?

Ответ №1:

Создайте карту League рангов по originalId , предоставьте ее вашему компаратору и используйте ее. Если вы ничего не можете найти на карте, установите use Integer .MIN_VALUE (или MAX_VALUE, в зависимости от того, какой способ вы хотите упорядочить). Это упорядочило бы его до конца результата. Что-то вроде (немного псевдокода):

 public static Comparator<Category> byRank(Map<String, Integer> leagueRanks) {
    return new Comparator<Category>() {
      @Override
      public int compare(Category o1, Category o2) {
        return Integer.compare(leagueRanks.getOrDefault(o1.getOriginalId(), Integer.MAX_VALUE), leagueRanks.getOrDefault(o2.getOriginalId(), Integer.MAX_VALUE));
      }
    };
}
 

Для сбора League рангов для сопоставления вы можете использовать что-то вроде этого:

 Map<String, Integer> leagueRanks = leagues.stream().collect(Collectors.toMap(it -> it.getOriginalId(), it -> it.getRank()));