簡體   English   中英

在Java 8中以慣用方式枚舉對象流

[英]Idiomatically enumerating a Stream of objects in Java 8

如何習慣地枚舉Stream<T> ,它使用Java 8流方法將每個T實例映射到唯一的整數(例如,對於數組T[] values ,創建Map<T,Integer> ,其中Map.get(values[i]) == i評估為true )?

目前,我正在定義一個匿名類,它增加一個int字段以與Collectors.toMap(..)方法一起使用:

private static <T> Map<T, Integer> createIdMap(final Stream<T> values) {
    return values.collect(Collectors.toMap(Function.identity(), new Function<T, Integer>() {

        private int nextId = 0;

        @Override
        public Integer apply(final T t) {
            return nextId++;
        }

    }));
}

但是,使用Java 8流API是否沒有更簡潔/更優雅的方式? - 如果可以安全地並行化,則可獲得獎勵積分。

如果存在重復元素,您的方法將失敗。

除此之外,您的任務需要可變狀態,因此可以通過Mutable減少來解決。 當我們填充地圖時,我們可以簡單地使用地圖的大小來獲取未使用的ID。

更棘手的部分是合並操作。 以下操作只是重復右圖的分配,這將處理潛在的重復。

private static <T> Map<T, Integer> createIdMap(Stream<T> values) {
    return values.collect(HashMap::new, (m,t) -> m.putIfAbsent(t,m.size()),
        (m1,m2) -> {
            if(m1.isEmpty()) m1.putAll(m2);
            else m2.keySet().forEach(t -> m1.putIfAbsent(t, m1.size()));
        });
}

如果我們依賴於唯一元素,或者插入一個顯式distinct() ,我們就可以使用

private static <T> Map<T, Integer> createIdMap(Stream<T> values) {
    return values.distinct().collect(HashMap::new, (m,t) -> m.put(t,m.size()),
        (m1,m2) -> { int leftSize=m1.size();
            if(leftSize==0) m1.putAll(m2);
            else m2.forEach((t,id) -> m1.put(t, leftSize+id));
        });

}

我會這樣做:

private static <T> Map<T, Integer> createIdMap2(final Stream<T> values) {
    List<T> list = values.collect(Collectors.toList());
    return IntStream.range(0, list.size()).boxed()
            .collect(Collectors.toMap(list::get, Function.identity()));
}

為了清酒或並行,可以將其更改為

   return IntStream.range(0, list.size()).parallel().boxed().
                (...)

比較在Andremoniy提供的解決方案中首先將輸入流轉換為List。 我寧願以不同的方式做到這一點,因為我們不知道“toList()”和“list.get(i)”的成本,並且沒有必要創建一個額外的List,它可以是小的或更大的

private static <T> Map<T, Integer> createIdMap2(final Stream<T> values) {
    final MutableInt idx = MutableInt.of(0); // Or: final AtomicInteger idx = new AtomicInteger(0);        
    return values.collect(Collectors.toMap(Function.identity(), e -> idx.getAndIncrement()));
}

無論問題如何,我認為將流作為參數傳遞給方法是一種糟糕的設計。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM