Ed-Genesis
Ed-Genesis

Reputation: 117

Sort a list by another list

I have a little problem that is driving me crazy.

I have a

I have to sort the second list by putting at the top the elements with id contained in the first list, then by string asc and by the second string asc.

What is the easiest way to make this work? I am trying to use the .sort(), Comparators etc.

An example:

@Getter
@Setter
public class ObjectA {
      private Integer id;
      private String code;
      private String name;
}

// comparator:
    static class SortByCode implements Comparator<ObjectA> {
        public int compare(ObjectA a, ObjectA b) {
            String as = a.getCode();
            String bs = b.getCode();

            return as.compareTo(bs);
        }
    }
    static class SortByName implements Comparator<ObjectA> {
        public int compare(ObjectA a, ObjectA b) {
            String as = a.getName();
            String bs = b.getName();

            return as.compareTo(bs);
        }
    }

// then in service:  
List<Integer> idsPreferred = new ArrayList<>();
List<ObjectA> listObj = new ArrayList<>();

idsPreferred = .... add preferred ids;
listObj = .... add objects;  
listObj.sort(new SortByCode()).thenComparing(new SortByName());

With this i sort by code and by name - but i need to add the sorting by the first list - I need the elements that have an id contained in the List to come before the others.

Upvotes: 0

Views: 189

Answers (2)

Sergey Afinogenov
Sergey Afinogenov

Reputation: 2202

I suppose something like this using chained comparing by extracted key:

listObj.sort(Comparator.comparing(o -> !idsPreferred.contains(((ObjectA) o).getId()))
                       .thenComparing(o -> ((ObjectA) o).getId())
                       .thenComparing(o -> ((ObjectA) o).getCode())
                       .thenComparing(o -> ((ObjectA) o).getName()));

or

listObj.sort(Comparator.comparing(ObjectA::getId,
                                  (id1,id2)-> {if (!((idsPreferred.contains(id1))^idsPreferred.contains(id2)))
                                                  return 0;
                                               else return (idsPreferred.contains(id2))?1:-1;})
                       .thenComparing(ObjectA::getId)
                       .thenComparing(ObjectA::getCode)
                       .thenComparing(ObjectA::getName));

Upvotes: 4

Caffeine Coder
Caffeine Coder

Reputation: 1146

The solution will involve 2 steps-

  1. check id of objects from second list, which are present in first list.
  2. Sort the contained objects using either of the solutions suggested- How to sort List of objects by some property

Upvotes: -1

Related Questions