1

The issue is to sort a huge collection of POJO objects

class Entity{
    String key1;
    String key2;
    String key3;
    String key4;
}

in alphabetical order by all of fields subsequently. That means that first we are sorting by key1, then by key2 and etc. Any of that key can be null. The question is the simplest way to do that.

Viktor Stolbin
  • 2,899
  • 4
  • 32
  • 53
  • 1
    possible duplicate of [Is this a correct way of sorting by title, position and then order by using a Comparator?](http://stackoverflow.com/questions/3823608/is-this-a-correct-way-of-sorting-by-title-position-and-then-order-by-using-a-co) – Thilo Jul 05 '12 at 09:03
  • 1
    You can probably get an idea or two from this answer: http://stackoverflow.com/a/481836/1343161 – Keppil Jul 05 '12 at 09:03
  • 1
    also: http://stackoverflow.com/questions/8036429/sorting-java-objects-using-multiple-keys?rq=1 – Thilo Jul 05 '12 at 09:04
  • Thanks a lot for all examples I've miss in my searching results – Viktor Stolbin Jul 05 '12 at 09:37

2 Answers2

2
private static int nullSafeCompare(String a, String b){
    if (a==b) return 0;
    if (a == null) return -1;
    if (b == null) return 1;
    return a.compareTo(b);
}


int compare(Entity a, Entity b){
   // if a and b can also be null:
   if (a==b) return 0;
   if (a==null) return -1;
   if (b==null) return 1;

   int c = nullSafeCompare(a.key1, b.key1);
   if (c != 0) return c;

   c = nullSafeCompare(a.key2, b.key2);
   if (c != 0) return c;

   c = nullSafeCompare(a.key3, b.key3);
   if (c != 0) return c;

   return nullSafeCompare(a.key4, b.key4);
}
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • This assumes, of course, that having nulls for any of these keys doesn't represent a bug, in which case you should go ahead and throw the NPE. – Louis Wasserman Jul 05 '12 at 09:19
  • Yes. Being able to handle null was mentioned in the question. Normally, a NPE is fine as well. – Thilo Jul 05 '12 at 10:29
1

A good way to do append all keys together and then use a Comparator<Entity> -

// all the keys of an entity are appended and than compared with other entity
int compare(Entity e1, Entity e2){
  return appendAndHandleNull(e1.key1, e1.key2, e1.key3).compareTo(appendAndHandleNull(e2.key1, e2.key2, e2.key3));
}



/** 
 * method to get all keys of an entity in appended form
 */
private static final String appendAndHandleNull(String list...){
   StringBuilder result = new StringBuilder ();
   for(String s : list){
      result.append(s!=null?s:"").append(" ");//note: a space is appended after each key
   }
   return result.toString();
}

What i am doing here is..... all the keys of an entity are appended together in the order in which comparison need to be done, and then compared with the other entity.

you might also need to trim each value before appending.

EDITED: It is also necessary to seperate each key by space for code to work properly.

Code fixed above. Thanks @Thilo for pointing it.

Kshitij
  • 8,474
  • 2
  • 26
  • 34
  • Appending all keys together might not work well if they are of different length, though: `{'AB', 'C'}` should come *after* `{'A', 'BD'}`, even though `ABC` sorts *before* `ABD`. – Thilo Jul 05 '12 at 10:31
  • All keys should be separated by spaces. – Marko Topolnik Jul 05 '12 at 10:35
  • yes you are right...possible solution can be append `space` at end of each key. So `result.append(s!=null?s:" ";)` will become `result.append(s!=null?s:"";).append(" ")`. This way i guess now if we compare `{'AB', 'C '}` and `{'A ', 'BD'}`... this should give right answer...correct me if i am wrong – Kshitij Jul 05 '12 at 10:37
  • Unless keys can contains spaces themselves. – Thilo Jul 05 '12 at 11:56
  • or maybe not...you are right again.... `{'A','C'}` should come before `{'A B'}`..but it will not. Possible solution i can think of is use a different `dilimiter` instead of `space` which will has lower order but will not be used inside the keys. – Kshitij Jul 05 '12 at 12:09
  • I used "|" delimiter. It works well for me due the data specificity. – Viktor Stolbin Jul 05 '12 at 18:14