去年、書いたStream の終端処理 Collector 以下は、
リストから重複要素を抽出する。 - Oboe吹きプログラマの黙示録
並行Stream実行ではNGであるのを反省して、以下のように修正すべきです。
static <T> Collector<T, Map<T, Integer>, List<T>> duplicatedList(){ return Collector.of(HashMap::new, (r, t)->r.put(t, Optional.ofNullable(r.get(t)).map(i->i+1).orElse(1)), (a1, a2)->{ a1.entrySet().stream().forEach(e->{ a2.put(e.getKey(), Optional.ofNullable(a2.get(e.getKey())) .map(i->i+e.getValue()).orElse(e.getValue())); }); return a2; }, a->a.entrySet().stream().filter(e->e.getValue() > 1) .map(e->e.getKey()) .collect(Collectors.toList()), Characteristics.CONCURRENT ); }
java.util.stream.Collector.Characteristics の指定
CONCURRENT | マルチスレッドで呼ばれても大丈夫な場合に指定する。 |
UNORDERED | 順序を保証しない場合に指定する。 |
IDENTITY_FINISH | finisherが省略可能 |
メソッド名、duplicatedList というのは、あまり良い名称に思えませんが、
重複カウント数を指定するなら以下です。
static <T> Collector<T, Map<T, Integer>, List<T>> duplicateCountOverList(int cnt){ return Collector.of(HashMap::new, (r, t)->r.put(t, Optional.ofNullable(r.get(t)).map(i->i+1).orElse(1)), (a1, a2)->{ a1.entrySet().stream().forEach(e->{ a2.put(e.getKey(), Optional.ofNullable(a2.get(e.getKey())) .map(i->i+e.getValue()).orElse(e.getValue())); }); return a2; }, a->a.entrySet().stream().filter(e->e.getValue() > cnt) .map(e->e.getKey()) .collect(Collectors.toList()), Characteristics.CONCURRENT ); }
しかし、やはり以下のように Collectors.groupingBy を使って書くことの方が多いかな?
List<String> res =
list.stream().collect(Collectors.groupingBy(t->t, Collectors.counting()))
.entrySet().stream().filter(e->e.getValue() == 2)
.map(e->e.getKey())
.collect(Collectors.toList());