简体   繁体   中英

Efficient way to sort a list by several comparators in Java

Sorry for my English.

I have something like this:

class SomeClass<T> {
    private List<T> elements;
    private List<Comparator<T>> comparators;

    public SomeClass(List<T> elements) {
        this.elements = elements;
        this.comparators = new ArrayList<Comparator<T>>();
    }

    public void addComparator(Comparator<T> comparator) {
        comparators.add(comparator);
    }

    public List<T> getSortedElements() {
        return sorted(new ArrayList<T>(elements));
    }

    // !!! At the moment I use very inefficient way
    // !!! to sort elements by several comparators.
    private List<T> sorted(List<T> toSort) {
        // I need to use stable sort.
        // Collections.sort(...) is guaranteed to be stable
        for (Comparator<T> comparator : comparators) {
            Collections.sort(toSort, comparator);
        }
        return toSort;
    }
}

Can I optimize sorted() method ? Maybe this can be done using a single sorting of collection by using combined comparator? (instead of sorting several times with each of comparators)

(But I have to use a stable sort, and last-added comparators have a higher priority than comparators added at the beginning)

UPDATE:

I use sorting by several comparators to sort elements by different attributes (for example, by priority, name, etc.)

The problem is that when you sort it the way you are doing, subsequent sorts completely discard the sorting done by previous sorts.

I think what you're wanting is to say something like "if the first comparator finds them equal, sort by the next". You can do that like this:

class SomeClass<T> {
    private List<T> elements;
    private List<Comparator<T>> comparators;

    private final Comparator<T> combined = new Comparator<T>() {
        @Override
        public int compare(T e1, T e2) {
            for(Comparator<T> c : comparators) {
                int result = c.compare(e1, e2);

                if(result != 0)
                    return result;
            }

            return 0;
        }
    };

    ...

    private List<T> sorted(List<T> toSort) {
        Collections.sort(toSort, combined);

        return toSort;
    }
}

Using Guava :

static <T> Comparator<T> compound(List<Comparator<T>> comparators)
{
    return Ordering.compound(comparators);
}

Given a pair of elements, the comparators in the given list are tried one after the other, in order, until one produces a non-zero result, which is returned, or there are no comparators left, in which case zero is returned.

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