Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort object List by another List using Java Comparators

Thare are two input lists as follows:

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

inputB = ["D", "B"]

My preferred output list must be as follows:

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

What I have done so far looks like below:

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()));

The output I am getting is as follows

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

Problem is with the elements that doesn't have their name in the list inputB. There order doesn't have the original order in inputA. For the original order to persist { name: "A", age: 20 } should come before { name: "C", age: 25 }

How can i solve this issue while using the comparator chaining strategy?

UPDATE Sorting logic is, if inputA has objects where the names are equal to the inputB list, those elements should come to the top of the inputA and then those elements must be sorted by their age while keeping the original order of the other elements in inputA which are not present in inputB

This is not a possible duplicate, because this question tries to compare two lists and also sort the common elements by a property of an object from the the first list while leaving the rest of the elements in their original order.

like image 312
simplelenz Avatar asked Feb 06 '19 18:02

simplelenz


People also ask

How do I sort a list in Comparator?

To sort an ArrayList using Comparator we need to override the compare() method provided by comparator interface. After rewriting the compare() method we need to call collections. sort() method like below.

How does Java sort with Comparator?

In Java, we can implement whatever sorting algorithm we want with any type. Using the Comparable interface and compareTo() method, we can sort using alphabetical order, String length, reverse alphabetical order, or numbers. The Comparator interface allows us to do the same but in a more flexible way.


1 Answers

As I see it, you need to sort elements by age if the name is contained in the inputB list and leave the rest of the elements as they are if they aren't contained in the inputB list. The elements sorted by age should appear at the top of the result, while the unsorted ones should appear at the bottom.

If this is what you need to do, you can use Comparator.comparingInt and let it return an integer that is either the age (for the first case) or Integer.MAX_VALUE (for the other case).

You should optimize the check over inputB, so that it is fast. For this, you could create a HashSet from inputB.

This is the code:

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

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

This works, as long as you don't have an age that is equal to Integer.MAX_VALUE.

The idea is that you always compare by age, but if an element doesn't belong to inputB, you turn the age into Integer.MAX_VALUE. This will have two effects: first, it will make elements not contained in inputB appear at the bottom; second, as you always return Integer.MAX_VALUE, the order of the inputA list is preserved, because Collections.sort implements a stable sort.

like image 109
fps Avatar answered Nov 15 '22 05:11

fps