用谓词对集合进行分区的库方法

我有一个对象集合,我想分成两个集合,其中一个传递谓词,其中一个不通过谓词。 我希望有一个Guava方法可以做到这一点,但它们最接近的是filter ,它不会给我另一个集合。

我想图像方法的签名将是这样的:

public static  Pair<Collection, Collection> partition(Collection source, Predicate predicate) 

我意识到这对我自己的编码速度非常快,但我正在寻找一种能够实现我想要的现有库方法。

使用Guava的Multimaps.index

下面是一个示例,它将单词列表分为两部分:长度> 3的那些和不具有长度> 3的部分。

 List words = Arrays.asList("foo", "bar", "hello", "world"); ImmutableListMultimap partitionedMap = Multimaps.index(words, new Function(){ @Override public Boolean apply(String input) { return input.length() > 3; } }); System.out.println(partitionedMap); 

打印:

 false=[foo, bar], true=[hello, world] 

使用新的java 8function( 流和lambda epressions ),您可以编写:

 List words = Arrays.asList("foo", "bar", "hello", "world"); Map> partitionedMap = words.stream().collect( Collectors.partitioningBy(word -> word.length() > 3)); System.out.println(partitionedMap); 

如果您正在使用Eclipse Collections (以前称为GS Collections),则可以对所有RichIterables使用partition方法。

 MutableList integers = FastList.newListWith(-3, -2, -1, 0, 1, 2, 3); PartitionMutableList 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产生两个集合而不是列表。

 MutableCollection integers = ...; PartitionMutableCollection result = integers.partition(IntegerPredicates.isEven()); MutableCollection selected = result.getSelected(); 

如果您的集合不是RichIterable ,您仍然可以在Eclipse集合中使用静态实用程序。

 PartitionIterable partitionIterable = Iterate.partition(integers, IntegerPredicates.isEven()); PartitionMutableList partitionList = ListIterate.partition(integers, IntegerPredicates.isEven()); 

注意:我是Eclipse Collections的提交者。

Apache Commons Collections IterableUtils提供了基于一个或多个谓词对可Iterable对象进行分区的Iterable 。 (查找partition(...)方法。)

注意,在预先已知的部分密钥的有限集合的情况下,对于每次迭代中跳过所有不同密钥项的每个分区密钥,再次迭代集合可能更加有效。 因为这不会为垃圾收集器分配许多新对象。

 LocalDate start = LocalDate.now().with(TemporalAdjusters.firstDayOfYear()); LocalDate endExclusive = LocalDate.now().plusYears(1); List daysCollection = Stream.iterate(start, date -> date.plusDays(1)) .limit(ChronoUnit.DAYS.between(start, endExclusive)) .collect(Collectors.toList()); List 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>> 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