我有一个对象集合,我想将它们分成两个集合,其中一个集合传递谓词,其中一个集合未通过谓词。我希望有一个Guava方法可以做到这一点,但它们最接近的是filter,它不会给我另一个集合。
我会想象方法的签名是这样的:
public static <E> Pair<Collection<E>, Collection<E>> partition(Collection<E> source, Predicate<? super E> predicate)
我意识到这对我自己的代码来说速度非常快,但我正在寻找能够实现我想要的现有库方法。
答案 0 :(得分:24)
使用番石榴Multimaps.index
。
这是一个示例,它将单词列表分为两部分:长度为&gt;的部分。 3和那些不要。
List<String> words = Arrays.asList("foo", "bar", "hello", "world");
ImmutableListMultimap<Boolean, String> partitionedMap = Multimaps.index(words, new Function<String, Boolean>(){
@Override
public Boolean apply(String input) {
return input.length() > 3;
}
});
System.out.println(partitionedMap);
打印:
false=[foo, bar], true=[hello, world]
答案 1 :(得分:11)
使用新的java 8功能(stream和lambda epressions),您可以写:
List<String> words = Arrays.asList("foo", "bar", "hello", "world");
Map<Boolean, List<String>> partitionedMap =
words.stream().collect(
Collectors.partitioningBy(word -> word.length() > 3));
System.out.println(partitionedMap);
答案 2 :(得分:3)
如果您使用的是Eclipse Collections(以前称为GS Collections),则可以对所有partition
使用RichIterables
方法。
MutableList<Integer> integers = FastList.newListWith(-3, -2, -1, 0, 1, 2, 3);
PartitionMutableList<Integer> result = integers.partition(IntegerPredicates.isEven());
Assert.assertEquals(FastList.newListWith(-2, 0, 2), result.getSelected());
Assert.assertEquals(FastList.newListWith(-3, -1, 1, 3), result.getRejected());
使用自定义类型PartitionMutableList
而不是Pair
的原因是允许getSelected()和getRejected()的协变返回类型。例如,对MutableCollection
进行分区会产生两个集合而不是列表。
MutableCollection<Integer> integers = ...;
PartitionMutableCollection<Integer> result = integers.partition(IntegerPredicates.isEven());
MutableCollection<Integer> selected = result.getSelected();
如果您的集合不是RichIterable
,您仍然可以在Eclipse集合中使用静态实用程序。
PartitionIterable<Integer> partitionIterable = Iterate.partition(integers, IntegerPredicates.isEven());
PartitionMutableList<Integer> partitionList = ListIterate.partition(integers, IntegerPredicates.isEven());
注意:我是Eclipse Collections的提交者。
答案 3 :(得分:0)
Apache Commons Collections IterableUtils
提供了基于一个或多个谓词对Iterable
个对象进行分区的方法。 (查找partition(...)
方法。)
答案 4 :(得分:0)
注意,在预先已知的partiotion密钥的有限集合的情况下,对于每个迭代中跳过所有不同密钥项的每个分区密钥,再次迭代集合可能更有效。因为这不会为垃圾收集器分配许多新对象。
LocalDate start = LocalDate.now().with(TemporalAdjusters.firstDayOfYear());
LocalDate endExclusive = LocalDate.now().plusYears(1);
List<LocalDate> daysCollection = Stream.iterate(start, date -> date.plusDays(1))
.limit(ChronoUnit.DAYS.between(start, endExclusive))
.collect(Collectors.toList());
List<DayOfWeek> keys = Arrays.asList(DayOfWeek.values());
for (DayOfWeek key : keys) {
int count = 0;
for (LocalDate day : daysCollection) {
if (key == day.getDayOfWeek()) {
++count;
}
}
System.out.println(String.format("%s: %d days in this year", key, count));
}
另一种GC友好和封装的方法是在原始集合周围使用Java 8过滤包装器流:
List<AbstractMap.SimpleEntry<DayOfWeek, Stream<LocalDate>>> partitions = keys.stream().map(
key -> new AbstractMap.SimpleEntry<>(
key, daysCollection.stream().filter(
day -> key == day.getDayOfWeek())))
.collect(Collectors.toList());
// partitions could be passed somewhere before being used
partitions.forEach(pair -> System.out.println(
String.format("%s: %d days in this year", pair.getKey(), pair.getValue().count())));
两个片段都打印出来:
MONDAY: 57 days in this year
TUESDAY: 57 days in this year
WEDNESDAY: 57 days in this year
THURSDAY: 57 days in this year
FRIDAY: 56 days in this year
SATURDAY: 56 days in this year
SUNDAY: 56 days in this year
答案 5 :(得分:0)
对于新的Java 12 "firefox-beta": {
"default": "beta",
"versions": {
"beta": {
"image": "my/path/to/firefox:beta",
"port": "4444"
}
}
}
Collectors::teeing