filter and sort list using google collections
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.
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.
Have a look at This Google Collections example.
Function<Fruit, String> getNameFunction = new Function<Fruit, String>() {
public String apply(Fruit from) {
return from.getName();
}
};
Ordering<Fruit> nameOrdering = Ordering.natural().onResultOf(getNameFunction);
ImmutableSortedSet<Fruit> sortedFruits = ImmutableSortedSet.orderedBy(
nameOrdering).addAll(fruits).build();
Though this, admittedly, returns a Set.
I think you'll have first to use the predicate to eliminate elements you don't want, and the implement a Comparator and sort your list.
Usually it's bad design to collate clearly distinct data like this. In your case, when you say "assocX", "assoc" has a separate meaning from "X", yet you merge them together.
So I would suggest designing a class with two fields. Then you can create an ordering on the first field, another on the second, and combine them (e.g. Ordering#compound()). With a toString() method that does merge these fields into a string. As a bonus, this may greatly reduce memory usage via sharing.
So you would be sorting a list of such objects, and if you wanted to print them, you would just call toString() on them.
精彩评论