In Java how do you sort one list based on another?

Solution 1:

Using Java 8:

Collections.sort(listToSort, 
    Comparator.comparing(item -> listWithOrder.indexOf(item)));

or better:

listToSort.sort(Comparator.comparingInt(listWithOrder::indexOf));

Solution 2:

Collections.sort(listB, new Comparator<Item>() {
    public int compare(Item left, Item right) {
        return Integer.compare(listA.indexOf(left), listA.indexOf(right));
    }
});

This is quite inefficient, though, and you should probably create a Map<Item, Integer> from listA to lookup the positions of the items faster.

Guava has a ready-to-use comparator for doing that: Ordering.explicit()

Solution 3:

Let's say you have a listB list that defines the order in which you want to sort listA. This is just an example, but it demonstrates an order that is defined by a list, and not the natural order of the datatype:

List<String> listB = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday");

Now, let's say that listA needs to be sorted according to this ordering. It's a List<Item>, and Item has a public String getWeekday() method.

Create a Map<String, Integer> that maps the values of everything in listB to something that can be sorted easily, such as the index, i.e. "Sunday" => 0, ..., "Saturday" => 6. This will provide a quick and easy lookup.

Map<String, Integer> weekdayOrder = new HashMap<String, Integer>();
for (int i = 0; i < listB.size(); i++)
{
    String weekday = listB.get(i);
    weekdayOrder.put(weekday, i);
}

Then you can create your custom Comparator<Item> that uses the Map to create an order:

public class ItemWeekdayComparator implements Comparator<Item>
{
    private Map<String, Integer> sortOrder;

    public ItemWeekdayComparator(Map<String, Integer> sortOrder)
    {
        this.sortOrder = sortOrder;
    }

    @Override
    public int compare(Item i1, Item i2)
    {
        Integer weekdayPos1 = sortOrder.get(i1.getWeekday());
        if (weekdayPos1 == null)
        {
            throw new IllegalArgumentException("Bad weekday encountered: " +
               i1.getWeekday());
        }
        Integer weekdayPos2 = sortOrder.get(i2.getWeekday());
        if (weekdayPos2 == null)
        {
            throw new IllegalArgumentException("Bad weekday encountered: " +
               i2.getWeekday());
        }
        return weekdayPos1.compareTo(weekdayPos2);
    }
}

Then you can sort listA using your custom Comparator.

Collections.sort(listA, new ItemWeekdayComparator(weekdayOrder));

Solution 4:

Speed improvement on JB Nizet's answer (from the suggestion he made himself). With this method:

  • Sorting a 1000 items list 100 times improves speed 10 times on my unit tests.

  • Sorting a 10000 items list 100 times improves speed 140 times (265 ms for the whole batch instead of 37 seconds) on my unit tests.

This method will also work when both lists are not identical:

/**
 * Sorts list objectsToOrder based on the order of orderedObjects.
 * 
 * Make sure these objects have good equals() and hashCode() methods or
 * that they reference the same objects.
 */
public static void sortList(List<?> objectsToOrder, List<?> orderedObjects) {

    HashMap<Object, Integer> indexMap = new HashMap<>();
    int index = 0;
    for (Object object : orderedObjects) {
        indexMap.put(object, index);
        index++;
    }

    Collections.sort(objectsToOrder, new Comparator<Object>() {

        public int compare(Object left, Object right) {

            Integer leftIndex = indexMap.get(left);
            Integer rightIndex = indexMap.get(right);
            if (leftIndex == null) {
                return -1;
            }
            if (rightIndex == null) {
                return 1;
            }

            return Integer.compare(leftIndex, rightIndex);
        }
    });
}

Solution 5:

Problem : sorting a list of Pojo on the basis of one of the field's all possible values present in another list.

Take a look at this solution, may be this is what you are trying to achieve:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Test {

  public static void main(String[] args) {
    List<Employee> listToSort = new ArrayList<>();
    listToSort.add(new Employee("a", "age11"));
    listToSort.add(new Employee("c", "age33"));
    listToSort.add(new Employee("b", "age22"));
    listToSort.add(new Employee("a", "age111"));
    listToSort.add(new Employee("c", "age3"));
    listToSort.add(new Employee("b", "age2"));
    listToSort.add(new Employee("a", "age1"));

    List<String> listWithOrder = new ArrayList<>();
    listWithOrder.add("a");
    listWithOrder.add("b");
    listWithOrder.add("c");

    Collections.sort(listToSort, Comparator.comparing(item -> 
    listWithOrder.indexOf(item.getName())));
    System.out.println(listToSort);
  }

}


class Employee {
  String name;
  String age;

  public Employee(String name, String age) {
    super();
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public String getAge() {
    return age;
  }

  @Override
  public String toString() {
    return "[name=" + name + ", age=" + age + "]";
  }
}

O U T P U T [[name=a, age=age11], [name=a, age=age111], [name=a, age=age1], [name=b, age=age22], [name=b, age=age2], [name=c, age=age33], [name=c, age=age3]]