Java 使用谷歌集合过滤和排序列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2312849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
filter and sort list using google collections
提问by harschware
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.
我想找回一个 ImmutableList(Set),它以自然顺序对术语进行排序/分组,其中以“src”开头的术语首先是,“assoc”第二,“dest”最后。如果一个术语不包含这些,那么它应该从结果列表中删除。
Therefore the result here is "srcB", "srcT", "assocX", "destA".
因此这里的结果是“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.
我想我可以用 Iterables.filter 或 Predicates 的一些组合来做到这一点,但只是没有看到它。我认为必须有一种简洁的方法。
EDIT: A set in place of a list works as well.
编辑:代替列表的集合也有效。
采纳答案by Paul Blessing
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.
如果您开始添加更多前缀来过滤或排序,这个解决方案肯定不会很好地扩展,因为您必须不断更新过滤器和每个前缀的权重。
回答by Valentin Rocher
I think you'll have first to use the predicate to eliminate elements you don't want, and the implement a Comparatorand sort your list.
我认为您必须首先使用谓词来消除您不想要的元素,然后实现一个Comparator并对您的列表进行排序。
回答by extraneon
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.
诚然,这会返回一个 Set。
回答by Dimitris Andreou
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.
通常像这样整理清晰不同的数据是糟糕的设计。在您的情况下,当您说“assocX”时,“assoc”与“X”具有不同的含义,但您将它们合并在一起。
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 doesmerge these fields into a string. As a bonus, this may greatly reduce memory usage via sharing.
所以我建议设计一个有两个字段的类。然后您可以在第一个字段上创建一个排序,在第二个字段上创建另一个,并将它们组合起来(例如 Ordering#compound())。有了一个toString()方法确实这些字段合并为一个字符串。作为奖励,这可以通过共享大大减少内存使用。
So you would be sorting a list of such objects, and if you wanted to print them, you would just call toString() on them.
因此,您将对这些对象的列表进行排序,如果您想打印它们,只需对它们调用 toString() 即可。