115

I have a List of Objects like List<Object> p.I want to sort this list alphabetically using Object name field. Object contains 10 field and name field is one of them.

if (list.size() > 0) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(final Object object1, final Object object2) {
        return String.compare(object1.getName(), object2.getName());
        }
    } );
}

But there is nothing like String.compare..?

David Newcomb
  • 10,639
  • 3
  • 49
  • 62
Saurabh Kumar
  • 16,353
  • 49
  • 133
  • 212
  • 3
    How are you going to get the name? -- `Object`s don't have names. Do you mean using `.toString()`? – Matt Fenwick Dec 08 '11 at 14:35
  • `object1` and `object2` need to be of type `Campaign`, and the compare function is `object1.getName().compareTo(object2.getName())`. – Bart van Heukelom Dec 08 '11 at 15:43
  • You mix `List` and `Comparator`. You can't do that. Either you have `List` and `Comparator` or `List` and `Comparator` – viktor Dec 08 '11 at 15:53

18 Answers18

255

From your code, it looks like your Comparator is already parameterized with Campaign. This will only work with List<Campaign>. Also, the method you're looking for is compareTo.

if (list.size() > 0) {
  Collections.sort(list, new Comparator<Campaign>() {
      @Override
      public int compare(final Campaign object1, final Campaign object2) {
          return object1.getName().compareTo(object2.getName());
      }
  });
}

Or if you are using Java 1.8

list
  .stream()
  .sorted((object1, object2) -> object1.getName().compareTo(object2.getName()));

One final comment -- there's no point in checking the list size. Sort will work on an empty list.

Micho
  • 3,929
  • 13
  • 37
  • 40
Robert B
  • 3,195
  • 2
  • 16
  • 13
23

Using Java 8 Comparator.comparing:

list.sort(Comparator.comparing(Campaign::getName));
Oleksandr Pyrohov
  • 14,685
  • 6
  • 61
  • 90
18

The most correct way to sort alphabetically strings is to use Collator, because of internationalization. Some languages have different order due to few extra characters etc.

   Collator collator = Collator.getInstance(Locale.US);
   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return collator.compare(c1.getName(), c2.getName());
        }
       });
   }

If you don't care about internationalization use string.compare(otherString).

   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return c1.getName().compare(c2.getName());
        }
       });
   }
viktor
  • 1,277
  • 10
  • 16
13

Have a look at Collections.sort() and the Comparator interface.

String comparison can be done with object1.getName().compareTo(object2.getName()) or object2.getName().compareTo(object1.getName()) (depending on the sort direction you desire).

If you want the sort to be case agnostic, do object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase()).

tobiasbayer
  • 10,269
  • 4
  • 46
  • 64
  • and how do you suggest extracting that field called `nama` from the `Object` type? this answer is not complete. – amit Dec 08 '11 at 14:40
  • Name extraction depends on the type of the object. I supposed it is just a placeholder type. If you cannot give a more concrete type, you might end using reflection. – tobiasbayer Dec 08 '11 at 15:43
7
public class ObjectComparator implements Comparator<Object> {

    public int compare(Object obj1, Object obj2) {
        return obj1.getName().compareTo(obj2.getName());
    }

}

Please replace Object with your class which contains name field

Usage:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);
Jan Vorcak
  • 19,261
  • 14
  • 54
  • 90
3

Here is a version of Robert B's answer that works for List<T> and sorting by a specified String property of the object using Reflection and no 3rd party libraries

/**
 * Sorts a List by the specified String property name of the object.
 * 
 * @param list
 * @param propertyName
 */
public static <T> void sortList(List<T> list, final String propertyName) {

    if (list.size() > 0) {
        Collections.sort(list, new Comparator<T>() {
            @Override
            public int compare(final T object1, final T object2) {
                String property1 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object1);
                String property2 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object2);
                return property1.compareToIgnoreCase (property2);
            }
        });
    }
}


public static Object getSpecifiedFieldValue (String property, Object obj) {

    Object result = null;

    try {
        Class<?> objectClass = obj.getClass();
        Field objectField = getDeclaredField(property, objectClass);
        if (objectField!=null) {
            objectField.setAccessible(true);
            result = objectField.get(obj);
        }
    } catch (Exception e) {         
    }
    return result;
}

public static Field getDeclaredField(String fieldName, Class<?> type) {

    Field result = null;
    try {
        result = type.getDeclaredField(fieldName);
    } catch (Exception e) {
    }       

    if (result == null) {
        Class<?> superclass = type.getSuperclass();     
        if (superclass != null && !superclass.getName().equals("java.lang.Object")) {       
            return getDeclaredField(fieldName, type.getSuperclass());
        }
    }
    return result;
}
che javara
  • 748
  • 1
  • 8
  • 18
3

Try this:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
2

You can use sortThisBy() from Eclipse Collections:

MutableList<Campaign> list = Lists.mutable.empty();
list.sortThisBy(Campaign::getName);

If you can't change the type of list from List:

List<Campaign> list = new ArrayList<>();
ListAdapter.adapt(list).sortThisBy(Campaign::getName);

Note: I am a contributor to Eclipse Collections.

Nikhil Nanivadekar
  • 1,152
  • 11
  • 10
2

I found another way to do the type.

if(listAxu.size() > 0){
    Collections.sort(listAxu, Comparator.comparing(IdentityNamed::getDescricao));
}
2

something like

  List<FancyObject> theList = … ;
  Collections.sort (theList,
                    new Comparator<FancyObject> ()
                    { int compare (final FancyObject a, final FancyObject d)
                          { return (a.getName().compareTo(d.getName())); }});
BRPocock
  • 13,638
  • 3
  • 31
  • 50
1

If your objects has some common ancestor [let it be T] you should use List<T> instead of List<Object>, and implement a Comparator for this T, using the name field.

If you don't have a common ancestor, you can implement a Comperator, and use reflection to extract the name, Note that it is unsafe, unsuggested, and suffers from bad performance to use reflection, but it allows you to access a field name without knowing anything about the actual type of the object [besides the fact that it has a field with the relevant name]

In both cases, you should use Collections.sort() to sort.

amit
  • 175,853
  • 27
  • 231
  • 333
0
if(listAxu.size() > 0){
     Collections.sort(listAxu, new Comparator<Situacao>(){
        @Override
        public int compare(Situacao lhs, Situacao rhs) {            
            return lhs.getDescricao().compareTo(rhs.getDescricao());
        }
    });
 }
Holloway
  • 6,412
  • 1
  • 26
  • 33
0

@Victor's answer worked for me and reposting it here in Kotlin in case useful to someone else doing Android.

if (list!!.isNotEmpty()) {
   Collections.sort(
     list,
     Comparator { c1, c2 -> //You should ensure that list doesn't contain null values!
     c1.name!!.compareTo(c2.name!!)
   })
}
Francislainy Campos
  • 3,462
  • 4
  • 33
  • 81
0

You can use this:

List<Campaign> list = new ArrayList<>(); 
list.sort(Comparator.comparing(Campaign::getName));
0

In case property contains also NULL values you can use:

list.sort(Comparator.comparing(Campaign::getName, Comparator.nullsLast(Comparator.naturalOrder())));

This puts NULL values to the last positions in the ordered list.

michal.jakubeczy
  • 8,221
  • 1
  • 59
  • 63
0

This is assuming a list of YourClass instead of Object, as explained by amit.

You can use this bit from the Google Guava library:

Collections.sort(list, Ordering.natural()
  .onResultOf(new Function<String,YourClass>() {
  public String call(YourClass o) {
     return o.getName();
  }))
  .nullsLast();

The other answers which mention Comparator are not incorrect, since Ordering implements Comparator. This solution is, in my opinion, a little easier, though it may be harder if you're a beginner and not used to using libraries and/or "functional programming".

Copied shamelessly from this answer on my own question.

Community
  • 1
  • 1
Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
0

Using a selection Sort

for(int i = list.size() - 1; i > 0; i--){

  int max = i

  for(int j = 0; j < i; j++){
      if(list.get(j).getName().compareTo(list.get(j).getName()) > 0){
            max= j;
      }
  }

  //make the swap
  Object temp = list.get(i);
  list.get(i) = list.get(max);
  list.get(max) = temp;

}
Shizumaru18
  • 129
  • 1
  • 2
  • 8
  • (1) Why would he reinvent the wheel? what's wrong with `Collections.sort()`? (2) the list is of type `List`, and therefore `list.get(j).getName()` will not compile. (3) this solution is O(n^2), while using `Collections.sort()` is a better O(nlogn) solution. – amit Dec 08 '11 at 15:16
0

If you are using a List<Object> to hold objects of a subtype that has a name field (lets call the subtype NamedObject), you'll need to downcast the list elements in order to access the name. You have 3 options, the best of which is the first:

  1. Don't use a List<Object> in the first place if you can help it - keep your named objects in a List<NamedObject>
  2. Copy your List<Object> elements into a List<NamedObject>, downcasting in the process, do the sort, then copy them back
  3. Do the downcasting in the Comparator

Option 3 would look like this:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}
Mike E
  • 5,493
  • 1
  • 14
  • 15