Search code examples
javasortingarraylistjava-streamcomparator

How to sort a list of Java objects by an attribute contained in another list?


Is there any way to sort the list of objects by an attribute that another list contains?

For example I try to sort ArrayList customObjects of CustomObjects by the values of ArrayList models of Strings :

ArrayList<CustomObject> customObjects = new ArrayList<>();
customObjects.add(new CustomObject("Volvo", 1, "x1", 200, 4, 15000, true, 4));
customObjects.add(new CustomObject("Bmw", 2, "x2", 200, 4, 15000, true, 4));
customObjects.add(new CustomObject("Mercedes", 3, "x3", 200, 4, 15000, true, 4));
customObjects.add(new CustomObject("Alfa", 4, "x4", 200, 4, 15000, true, 4));
customObjects.add(new CustomObject("Fiat", 5, "x5", 200, 4, 15000, true, 4));

ArrayList<String> models = new ArrayList<>();
models.add("x2");
models.add("x5");
models.add("x1");
models.add("x4");
models.add("x3");

Expected result:

customObjects = [
  {CustomObject("Bmw", 2, "x2", 200, 4, 15000, true, 4))}
  {CustomObject("Fiat", 5, "x5", 200, 4, 15000, true, 4)}
  {CustomObject("Volvo", 1, "x1", 200, 4, 15000, true, 4)}
  {CustomObject("Alfa", 4, "x4", 200, 4, 15000, true, 4)}
  {CustomObject("Mercedes", 3, "x3", 200, 4, 15000, true, 4)}
]

Note that the list sizes could be different.


Solution

  • You can write your own comparator for that. I have called your string with X "xString" like this

    public class CustomObject {
    
        private final String volvo;
        private final int i;
        private final String xString;
        private final int i1;
        private final int i2;
        private final int i3;
        private final boolean b;
        private final int i4;
    
        public CustomObject(String volvo, int i, String type, int i1, int i2, int i3, boolean b, int i4) {
            this.volvo = volvo;
            this.i = i;
            this.xString = type;
            this.i1 = i1;
            this.i2 = i2;
            this.i3 = i3;
            this.b = b;
            this.i4 = i4;
        }
    
        public String getXString() {
            return xString;
        }
    
    }
    

    in your code you can then compare the indexes of the models list like this:

        @Test
        public void testSorting() {
    
            List<CustomObject> customObjects = new ArrayList<>();
            customObjects.add(new CustomObject("Volvo", 1, "x1", 200, 4, 15000, true, 4));
            customObjects.add(new CustomObject("Bmw", 2, "x2", 200, 4, 15000, true, 4));
            customObjects.add(new CustomObject("Mercedes", 3, "x3", 200, 4, 15000, true, 4));
            customObjects.add(new CustomObject("Alfa", 4, "x4", 200, 4, 15000, true, 4));
            customObjects.add(new CustomObject("Fiat", 5, "x5", 200, 4, 15000, true, 4));
    
    
            List<String> models = new ArrayList<>();
            models.add("x2");
            models.add("x5");
            models.add("x1");
            models.add("x4");
            models.add("x3");
    
            // Compator#compare returns int that tells which object is first and which second, see the Javadoc.
            // You can write your own comparator by just subtracting the indexes in the list.
            customObjects.sort((car1, car2) -> models.indexOf(car1.getXString()) - models.indexOf(car2.getXString()));
    
            System.out.println(customObjects);
        }
    

    This doesn't cope with corner cases like the property is not found in the list, null values etc.., but you could get the idea.

    Shorter way of sorting but less understandable for people not familiar with lambdas can look like this:

        customObjects.sort(Comparator.comparingInt(car -> models.indexOf(car.getXString())));