用谓词对集合进行分区的库方法
我有一个对象集合,我想分成两个集合,其中一个传递谓词,其中一个不通过谓词。 我希望有一个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