London
London

Reputation: 15274

Comparator based on a configurable order

Is there a way to write custom comparator, following this example:

There are at most 10 items coming in at a random order i.e.

first item:  item_one
second:      second_one
third:       third_one

I want result them to be sorted like : second_one, third_one, first_one. I'd like to pull this order from configuration file, sort of like template for sorting.

Am I using the wrong data structure, does anyone have experience with this?

Upvotes: 14

Views: 19937

Answers (4)

Andrew Ko
Andrew Ko

Reputation: 301

Use Guava's com.google.common.collect.Ordering:

Ordering.explicit(second_one, third_one, first_one);

Upvotes: 0

aioobe
aioobe

Reputation: 421090

Sure. Here is an "OrderedComparator" that compares elements according to a predefined order:

class OrderedComparator implements Comparator<String> {

    List<String> predefinedOrder;

    public OrderedComparator(String[] predefinedOrder) {
        this.predefinedOrder = Arrays.asList(predefinedOrder);
    }

    @Override
    public int compare(String o1, String o2) {
        return predefinedOrder.indexOf(o1) - predefinedOrder.indexOf(o2);
    }

}

And here is some test code. (I used a List instead of a Set since it 1) seem more natural when talking about the order of the elements and 2) better illustrate what happens with duplicate elements upon sorting using this comparator.)

class Test {

    public static void main(String[] args) {

        // Order (could be read from config file)
        String[] order = { "lorem", "ipsum", "dolor", "sit" };


        List<String> someList = new ArrayList<String>();

        // Insert elements in random order.
        someList.add("sit");
        someList.add("ipsum");
        someList.add("sit");
        someList.add("lorem");
        someList.add("dolor");
        someList.add("lorem");
        someList.add("ipsum");
        someList.add("lorem");


        System.out.println(someList);

        Collections.sort(someList, new OrderedComparator(order));

        System.out.println(someList);
    }

}

Output:

[sit, ipsum, sit, lorem, dolor, lorem, ipsum, lorem]
[lorem, lorem, lorem, ipsum, ipsum, dolor, sit, sit]

Upvotes: 19

Jonathan
Jonathan

Reputation: 13624

A set stores unordered elements. If you want to compare and sort, you should probably go with a list. Here's a quick snippet for you:

List<X> sorted = new ArrayList<X>(myset);
Collections.sort(sorted, new Comparator<X>() {
    public int compare(X o1, X o2) {
        if (/* o1 < o2 */) {
            return -1;
        } else if (/* o1 > o2 */) {
            return 1;
        } else {
            return 0;
        }
    }
});

Now you've got sorted, which has all the same elements of myset, which was unordered by virtue of being a set.

You can also look at TreeSet, which orders its elements, but it's generally not a good idea to rely on a set being ordered.

Upvotes: 1

David Soroko
David Soroko

Reputation: 9096

Take a look at TreeSet (http://download.oracle.com/javase/6/docs/api/java/util/TreeSet.html). You can provide a custom Comparator in a constructor. This Comparator will take into account your config. file . The logic of the comparator will not be pretty though since you want arbitrary order. You will most probably end up enumerating all possible comparisons.

Upvotes: 2

Related Questions