簡體   English   中英

用於 map 計算的流來自帶有計數器的列表

[英]Streams use for map computation from list with counter

我有以下 for 循環,我想用一個簡單的 Java 8 stream 語句替換它:

List<String> words = new ArrayList<>("a", "b", "c");
Map<String, Long> wordToNumber = new LinkedHashMap<>();
Long index = 1L;

for (String word : words) {
  wordToNumber.put(word, index++);
}

我基本上想要每個單詞的排序 map (按插入順序)到它的編號(在每個 for 循環中遞增 1),但如果可能的話,使用 Java 8 個流做得更簡單。

以下應該工作(雖然不清楚為什么需要Long因為List的大小是int

Map<String, Long> map = IntStream.range(0, words.size())
    .boxed().collect(Collectors.toMap(words::get, Long::valueOf));

如果words列表中沒有重復項,則上面的代碼有效。

如果可能出現重復單詞,則需要將合並 function 提供給 select,該索引應存儲在 map 中(第一個或最后一個)

Map<String, Long> map = IntStream.range(0, words.size())
    .boxed().collect(
        Collectors.toMap(words::get, Long::valueOf, 
        (w1, w2) -> w2, // keep the index of the last word as in the initial code
        LinkedHashMap::new // keep insertion order
    ));

同樣,map 可以通過流式傳輸words和使用外部變量來增加索引來構建(可以使用AtomicLonggetAndIncrement()代替long[] ):

long[] index = {1L};
Map<String, Long> map = words.stream()
    .collect(
        Collectors.toMap(word -> word, word -> index[0]++, 
        (w1, w2) -> w2, // keep the index of the last word
        LinkedHashMap::new // keep insertion order
    ));
   Map<String, Long> wordToNumber = 
   IntStream.range(0, words.size())
            .boxed()
            .collect(Collectors.toMap(
                    words::get,
                    x -> Long.valueOf(x) + 1,
                    (left, right) -> { throw new RuntimeException();},
                    LinkedHashMap::new
            ));

您可以替換它(left, right) -> { throw new RuntimeException();}取決於您要如何合並兩個元素。

稍微不同的解決方案。 Integer::max是合並 function 如果同一個單詞出現兩次就會被調用。 在這種情況下,它選擇最后一個 position ,因為這實際上是問題中的代碼示例所做的。

@Test
public void testWordPosition() {
    List<String> words = Arrays.asList("a", "b", "c", "b");
    AtomicInteger index = new AtomicInteger();
    Map<String, Integer> map = words.stream()
            .map(w -> new AbstractMap.SimpleEntry<>(w, index.incrementAndGet()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Integer::max));
    System.out.println(map);
}

Output:

{a=1, b=4, c=3}

編輯:

在評論中結合 Alex 的建議,它變成:

@Test
public void testWordPosition() {
    List<String> words = Arrays.asList("a", "b", "c", "b");
    AtomicLong index = new AtomicLong();
    Map<String, Long> map = words.stream()
            .collect(Collectors.toMap(w -> w, w -> index.incrementAndGet(), Long::max));
    System.out.println(map);
}

我基本上想要每個單詞的排序 map (按插入順序)到它的編號(在每個 for 循環中遞增 1),但如果可能的話,使用 Java 8 個流做得更簡單

您可以使用以下Stream簡潔地做到這一點:

AtomicLong index = new AtomicLong(1);
words.stream().forEach(word -> wordToNumber.put(word, index.getAndIncrement()));

就個人而言,我認為要么

Map<String, Long> wordToNumber = new LinkedHashMap<>();
for(int i = 0; i < words.size(); i++){
    wordToNumber.put(words.get(i), (long) (i + 1));
}

或者

Map<String, Long> wordToNumber = new LinkedHashMap<>();
for (String word : words) {
    wordToNumber.put(word, index++);
}

足夠簡單。

暫無
暫無

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

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