Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sort by nullable field saying the item's position

I need to sort my array of object in custom way. Let's say I have two field in my objects – priority (nullable) and createdAt (non-nullable). The priority field says at which position the item should be. It can be null, however. In that case we should sort taking into consideration createdAt field (with descending order).

Let me explain it with example. For example my objects would be:

Object0: priority: null, createdAt: 2018-12-01
Object1: priority: 1,    createdAt: 2018-12-02
Object2: priority: 5,    createdAt: 2018-12-03
Object3: priority: null, createdAt: 2018-12-04
Object4: priority: null, createdAt: 2018-12-05
Object5: priority: 2,    createdAt: 2018-12-06
Object6: priority: null, createdAt: 2018-12-07

The final order should be:

  1. Object1 (by its priority)
  2. Object5 (by its priority)
  3. Object6 (filling left positions by createdAt desc)
  4. Object4 (filling left positions by createdAt desc)
  5. Object2 (by its priority)
  6. Object3 (filling left positions by createdAt desc)
  7. Object0 (filling left positions by createdAt desc)

How could I achieve my goal? Is there any out-of-the-box comparator ready?

EDIT: I think we can use that class:

public class MyObject {
   Integer priority;
   LocalDateTime createdAt;
}
like image 739
michalsol Avatar asked Dec 29 '25 19:12

michalsol


2 Answers

Given a list of all the objects : an array would be good to set the position from the priority :

List<MyObject> list = new ArrayList<>(Arrays.asList(...));
MyObject[] res = new MyObject[list.size()];
  1. Iterate over the objects you have to place the ones that have a priority

    for (Iterator<MyObject> ite = list.iterator(); ite.hasNext(); ) {
        MyObject obj = ite.next();
        if (obj.getPriority() != null) {
            res[obj.getPriority() - 1] = obj;
            ite.remove();
        }
    }
    
  2. Sort the other by descending createdAt

    list.sort(Comparator.comparing(MyObject::getCreatedAt).reversed());
    
  3. Insert them in empty boxes of the array

    int indicList = 0;
    for (int i = 0; i < res.length; i++) {
        if (res[i] == null) {
            res[i] = list.get(indicList++);
        }
    }
    

  • Complete Example over here
like image 82
azro Avatar answered Dec 31 '25 11:12

azro


No, don’t use a comparator for this, or more precisely, not for the whole job. A comparator’s job is to compare two objects and tell the order between those two. It will not be suited for detecting gaps in the priority sequence.

Instead, assuming that priorities are integral and unique I suggest you use an array and a kind of radix sort for the objects with defined priorities. Priority 1 goes into array index 1, priority 2 index 2, etc. The objects with null priority are sorted with a comparator on creation date descending and are then filled into the array indices that are still null (except index 0, I guess).

By “assuming that priorities are integral and unique” I mean that you don’t risk two objects with priority 3 or an object with priority 2.44.

I might use a stream and Collectors.partitioningBy to separate the objects with priorities from those without priority, but there are other ways to do, of course.

I’d hand code this. I have never heard of any ready-made solution for it. Searching never harms, but I’d be surprised to find one. On the other hand, not that many lines of code will be needed.

BTW use LocalDate for your dates since they don’t have time of day (not LocalDateTime).

like image 44
Ole V.V. Avatar answered Dec 31 '25 09:12

Ole V.V.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!