2012-05-11 10 views
26

2つのコレクションに分割するオブジェクトのコレクションがあります。そのうちの1つは述語を渡し、もう1つは述語に失敗します。これを行うにはGuavaメソッドがあることを期待していましたが、最も近いものはfilterです。これは私に他のコレクションを与えません。述語でコレクションを分割するライブラリメソッド

私はイメージメソッドのシグネチャは、このようなものになるだろうう:

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

私は、これは自分自身をコーディングする超高速で実現するが、私は私が何をしたいん既存のライブラリの方法を探しています。

+0

注する場合のある別の双方GC向け及びカプセル化アプローチは、元のコレクションの周囲のJava 8フィルタリングラッパー・ストリームを使用している

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にはるかに効率的です。 – Vadzim

+0

GCに優しいアプローチとカプセル化されたアプローチのどちらも、元のコレクションの周囲にJava 8フィルタリングラッパーストリームを使用しています。https://stackoverflow.com/questions/19940319/can-you-split-a-stream-into-two-streams – Vadzim

答えて

24

グアバの​​を使用してください。

ここでは、単語のリストを2つの部分に分割する例を示します。長さが3以上の単語とそうでない単語の2つの部分に分割します。

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

ありがとうございます、私はそこを見ることを考えなかったでしょう。 –

+4

述語がすでにある場合は、Functions.forPredicateを含むFunctionに変換できます。 – roryparle

+4

Java 8用のアップデート:同様のメソッドがストリーミングパッケージ 'java.util.stream.Collectors#groupingBy(java.util.function.Function <....>)' にも用意されています。これは 'words.stream()のようになります。 (Collectors.groupingBy(func)) ' –

3

あなたはEclipse Collections(旧GSコレクション)を使用している場合、あなたはすべてのRichIterablespartitionメソッドを使用することができます。

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をパーティショニングすると、リストではなく2つのコレクションが得られます。

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

コレクションがRichIterableでない場合は、引き続きEclipse Collectionsで静的ユーティリティを使用できます。

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

注:私はEclipseのコレクションのためのコミッターです。新しいJava 8つの特徴(streamlambda epressions)で

8

、あなたが書くことができます:

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); 
0

Apache Commons CollectionsIterableUtilsは、一の以上の述語に基づいてIterableオブジェクトを分割するための方法を提供します。 (partition(...)の方法を参照してください)

0

事前に設定されている事前設定キーが限られている場合は、各パーティションキーごとにコレクションをもう一度繰り返して、それぞれのキー項目をすべてスキップするほうがずっと効率的です繰り返し。これは、ガベージコレクタに多くの新しいオブジェクトを割り当てないためです。

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 
関連する問題