简体   繁体   中英

Sorting a List of Objects Based on 1 of its Fields

Hello stackoverflow community! I am new to these forums and also fairly new to java and android programming--which happen to be the objects of my question--so sorry in advance for any blunders!

My issue is sorting. I am looking for a method to sort objects based on a field that I choose (not sorting based on the first field, then the next, etc. exemplified by comparator chaining). I believe I've found the solution to my problem:

https://stackoverflow.com/a/5113108/1549672

but I am having trouble actually getting this to work. I have a suspicion that I'm probably missing something due to my lack of java experience, so any help is welcome!

Here is what I am trying:

As my class-

public class ItemLocation {
String title;
int id;
}

As my function-

public void sort(final String field, List<ItemLocation> itemLocationList) {
    Collections.sort(itemLocationList, new Comparator<ItemLocation>() {
        @Override
        public int compare(ItemLocation o1, ItemLocation o2) {
            if(field.equals("title")) {
                return o1.title.compareTo(o2.title);
            } else if(field.equals("id")) {
                return Integer.valueOf(o1.id).compareTo(o2.id);
            }
            return 0;
        }
    });
}

using these, could someone possibly give an example of using this method? I attempted to fill an ArrayList and sort it, but to no avail.

Thanks for the help!

You should not return 0 from the Comparator.compare method if they are not equal. It's "okey" by the contract, but not exactly encouraged, from the API documentation:

It is generally the case, but not strictly required that (compare(x, y)==0) == (x.equals(y)). Generally speaking, any comparator that violates this condition should clearly indicate this fact. The recommended language is "Note: this comparator imposes orderings that are inconsistent with equals."


In my opinion you should return a specific Comparator for each field instead:

Comparator<ItemLocation> titleComparator = new Comparator<ItemLocation>() {
    @Override
    public int compare(ItemLocation o1, ItemLocation o2) {
        return o1.title.compareTo(o2.title);
    }
}

Comparator<ItemLocation> idComparator = new Comparator<ItemLocation>() {
    @Override
    public int compare(ItemLocation o1, ItemLocation o2) {
        return Integer.valueOf(o1.id).compareTo(o2.id);
    }
}

public void sort(final String field, List<ItemLocation> itemLocationList) {

    final Comparator<ItemLocation> comparator;

    if(field.equals("title")) {
        comparator = titleComparator;
    } else if (field.equals("id")) {
        comparator = idComparator;
    } else {
        throw new IllegalArgumentException("Comparator not found for " + field);
    }

    Collections.sort(itemLocationList, comparator);
}

Can you post the calling code that is not working? I can't see anything clearly wrong with the code you've provided.

Firstly, you might try is putting an extra else case like so:

else {
    throw new IllegalArgumentException("Unrecognised field name");
}

At the moment, if you had a typo in your calling code, the comparator would always return 0, which would leave the list unsorted.

A more robust way of passing the field would be to declare an enum:

enum ItemLocationField {
    TITLE,
    ID
}

Then your conditions would become:

if (field == ItemLocationField.TITLE)

and so on. That would reduce the chances of making a typo (the compiler will tell you if you do).

I don't see anything wrong except returning 0 and comparing parameter with equals . you can improve it by throwing RuntimeException rather than returning 0 and use equalsIgnoreCase rather than equals method , better to ignore the case of parameter.

public static void sort(final String field, List<ItemLocation> itemLocationList) {
    Collections.sort(itemLocationList, new Comparator<ItemLocation>() {
        @Override
        public int compare(ItemLocation o1, ItemLocation o2) {
            if(field.equalsIgnoreCase("title")) {
                return o1.title.compareTo(o2.title);
            } else if(field.equalsIgnoreCase("id")) {
                return Integer.valueOf(o1.id).compareTo(o2.id);
            }else
                throw new IllegalArgumentException("Invalid Parameter .");
        }
    });
}

1. If you want to Sort object on the basis of only one attribute , then go for java.lang.Comparable Interface along with Collections.sort(List<T> list)

2. If you want to Sort the object on the basis of more than one attributes , then go for java.util.Comparator Interface along with Collections.sort(List<T> list, Comparator<? super T> c)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM