Сортировать список объектов другим списком с помощью компараторов Java - PullRequest
0 голосов
/ 06 февраля 2019

Существует два следующих списка ввода:

inputA = [
            {
               name: "A",
               age: 20
            }, 
            {
               name: "B",
               age: 30
            },
            {  name: "C",
               age: 25
            },
            {  name: "D",
               age: 28
            }
          ]

inputB = ["D", "B"]

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

expectedOutput = [
            {
               name: "D",
               age: 28
            }, 
            {
               name: "B",
               age: 30
            },
            {  name: "A",
               age: 20
            },
            {  name: "C",
               age: 25
            }
          ]

То, что я сделал до сих пор, выглядит следующим образом:

AtomicInteger count = new AtomicInteger();
Collections.sort(inputA, Comparator
    .comparing(a -> 
    if (inputB.indexOf(a.getName()) > -1) {
        return -1;
    }
    else {
        return count.incrementAndGet();
    })
    .thenComparingInt(a -> a.getAge()));

Вывод, который я получаю, выглядит следующим образом

actualOutput = [
            {
               name: "D",
               age: 28
            }, 
            {
               name: "B",
               age: 30
            },
            {  name: "C",
               age: 25
            },
            {  name: "A",
               age: 20
            }
          ]

Проблема в том, что элементы не имеют своего имени в списке inputB.Там у заказа нет первоначального заказа в inputA.Для сохранения первоначального заказа { name: "A", age: 20 } должен предшествовать { name: "C", age: 25 }

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

ОБНОВЛЕНИЕ Логика сортировки такова: если у inputA есть объекты, имена которых совпадают со списком inputB, эти элементы должны располагаться в верхней части inputA, а затем эти элементы должны быть отсортированы повозраст при сохранении исходного порядка других элементов в inputA, которые не присутствуют во inputB

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

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

На мой взгляд, вам нужно отсортировать элементы по возрасту, если имя содержится в списке inputB, и оставить остальные элементы такими, какие они есть, если они не содержатся в списке inputB.Элементы, отсортированные по возрасту, должны отображаться вверху результата, а несортированные - внизу.

Если это то, что вам нужно сделать, вы можете использовать Comparator.comparingInt и позволить ему вернутьцелое число, которое является либо возрастом (для первого случая), либо Integer.MAX_VALUE (для другого случая).

Вы должны оптимизировать проверку по inputB, чтобы она была быстрой.Для этого вы можете создать HashSet из inputB.

Это код:

Set<String> set = new HashSet<>(inputB);

Collections.sort(inputA, Comparator.comparingInt(a -> set.contains(a.getName()) ? 
                                                      a.getAge() : 
                                                      Integer.MAX_VALUE));

Это работает, если у вас нет возраста, которыйравно Integer.MAX_VALUE.

Идея состоит в том, что вы всегда сравниваете по возрасту, но если элемент не принадлежит inputB, вы превращаете возраст в Integer.MAX_VALUE.Это будет иметь два эффекта: во-первых, снизу появятся элементы, не содержащиеся в inputB;во-вторых, как вы всегда возвращаете Integer.MAX_VALUE, порядок списка inputA сохраняется, потому что Collections.sort реализует стабильную сортировку .

0 голосов
/ 07 февраля 2019

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

Collections.sort(inputA, Comparator.comparing(a ->
{
    if (inputB.indexOf(a.getName()) > -1)
    {
        return 0;
    }
    return 1;
})
.thenComparingInt(a -> 
{
   if (inputB.indexOf(a.getName()) > -1)
   {
       return a.getAge();
   }
   return Integer.MAX_VALUE;
}));

Тем не менее, я не уверен, желательно ли дважды IndexOf(), особенно если inputB не отсортирован.Возможно, стоит взглянуть на сгенерированный байт-код, чтобы увидеть, оптимизируется ли он.

Одна вещь заключается в том, что использование счетчика не влияет на сравнение.Вам просто нужно вернуть -1, 0 или 1 в операции сравнения.Таким образом, нет смысла делать потокобезопасное приращение на счетчике.

С другой стороны, если вы можете, введите поле priority в классе, который определяет объект в inputA.Тогда вы можете обойти проблему вызова indexOf() несколько раз, например:

Collections.sort(inputA, Comparator.comparing(a ->
{
   if (inputB.indexOf(a.getName()) > -1)
   {
       a.setPriority(a.getAge());
       return 0;
   }

   a.setPriority(Integer.MAX_VALUE);
   return 1;
})
.thenComparingInt(a -> a.getPriority()));
...