整数のストリームを取得しました。要素のインデックスを各要素の値でグループ化したいと思います。
たとえば、{1, 1, 1, 2, 3, 3, 4}
は整数としてグループ化され、インデックスマッピングのリストになります。
1 -> 0, 1, 2
2 -> 3
3 -> 4, 5
4 -> 6
ストリームを使用してみましたが、クラスが追加されています。
@Test
public void testGrouping() throws Exception {
// actually it is being read from a disk file
Stream<Integer> nums = Stream.of(1, 1, 1, 2, 3, 3, 4);
// list to map by index
int[] ind = {0}; // capture array, effectively final
class Pair {
int left;
int right;
public Pair(int left, int right) {
this.left = left;
this.right = right;
}
}
Map<Integer, List<Integer>> map = nums.map(e -> new Pair(ind[0]++, e))
.collect(Collectors.groupingBy(e -> e.right))
.entrySet().parallelStream()
.collect(Collectors.toConcurrentMap(
Map.Entry::getKey,
e -> e.getValue().parallelStream().map(ee -> ee.left).collect(Collectors.toList())
));
}
Stream of Integerはアプリケーションのディスクファイルから読み取られるため、Streamを読み取る必要があります。
上記のように私のやり方はかなり最適ではないと感じています。それを行うためのより良いまたはよりエレガントな方法はありますか?
ご協力いただきありがとうございます。
収集のための少しのヘルパー方法で:
class MapAndIndex {
Map<Integer,List<Integer>> map=new HashMap<>();
int index;
void add(int value) {
map.computeIfAbsent(value, x->new ArrayList<>()).add(index++);
}
void merge(MapAndIndex other) {
other.map.forEach((value,list) -> {
List<Integer> l=map.computeIfAbsent(value, x->new ArrayList<>());
for(int i: list) l.add(i+index);
} );
index+=other.index;
}
}
操作全体は次のようになります。
Map<Integer,List<Integer>> map = IntStream.of(1, 1, 1, 2, 3, 3, 4)
.parallel()
.collect(MapAndIndex::new, MapAndIndex::add, MapAndIndex::merge).map;
事前に不明なインデックスを追跡する必要がある場合は、可変状態が必要であるため、「可変リダクション」と呼ばれる操作が必要です。
ConcurrentMap
ここは必要ないことに注意してください。Stream
実装は、すでに同時実行を処理します。MapAndIndex
関連するスレッドごとに1つのコンテナーを作成しmerge
、関連付けられた両方のスレッドの作業が完了すると、2つのコンテナーで操作を呼び出します。これはStream
、この例のように、が順序を持っている場合、順序を保持する方法でも行われます(そうでない場合、インデックスを記録するタスクは意味がありません…)。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加