filter and sort list using google collections

harschware picture harschware · Feb 22, 2010 · Viewed 46.8k times · Source

Suppose I have a list (or Set):

List<String> testList = Lists.newArrayList("assocX","srcT","destA","srcX", "don't care Y", "garbage", "srcB");

I would like to get back an ImmutableList(Set) that sorts/groups terms in natural order where terms that begin with "src" are first, "assoc" second and "dest" last. If a term does not contain those then it should be removed from the resulting list.

Therefore the result here is "srcB", "srcT", "assocX", "destA".

I think I can do this with some combination of Iterables.filter or Predicates but just not seeing it. There must be a succinct way of doing it I think.

EDIT: A set in place of a list works as well.

Answer

Paul Blessing picture Paul Blessing · Feb 22, 2010

As long as those three prefixes are the only things you care about, I'd suggest something like this:

    Predicate<String> filter = new Predicate<String>() {
        @Override
        public boolean apply(String input) {
            return input.startsWith("src") || input.startsWith("assoc") || input.startsWith("dest");
        }
    };

    Function<String, Integer> assignWeights = new Function<String, Integer>() {
        @Override
        public Integer apply(String from) {
            if (from.startsWith("src")) {
                return 0;
            } else if (from.startsWith("assoc")) {
                return 1;
            } else if (from.startsWith("dest")) {
                return 2;
            } else {
                /* Shouldn't be possible but have to do something */
                throw new IllegalArgrumentException(from + " is not a valid argument");
            }
        }
    };

    ImmutableList<String> sortedFiltered = ImmutableList.copyOf(
            Ordering.natural().onResultOf(assignWeights).sortedCopy(
                    Iterables.filter(testList, filter)
            )
    );

This solution definitely wouldn't scale out incredibly well if you start adding more prefixes to filter out or sort by, since you'd have to continually update both the filter and the weight of each prefix.