流用于从带有计数器的列表进行地图计算
Streams use for map computation from list with counter
我有以下 for 循环,我想用一个简单的 Java 8 流语句替换它:
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++);
}
我基本上想要每个单词与其编号(在每个 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
列表中没有重复项,则上面的代码有效。
如果可能有重复的词,需要提供一个合并功能select 哪个索引应该存储在地图中(第一个或最后一个)
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
));
类似地,可以通过流式传输 words
和使用外部变量来增加索引来构建地图(可以使用 AtomicLong
和 getAndIncrement()
代替 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();}
,具体取决于您希望如何 合并 两个元素。
I basically want a sorted map (by insertion order) of each word to its
number (which is incremented at each for loop by 1), but done simpler,
if possible with Java 8 streams.
您可以使用以下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++);
}
比较简单。
一个略有不同的解决方案。 Integer::max
是合并函数,如果同一个词出现两次,则会调用该函数。在这种情况下,它会选择最后一个位置,因为这实际上是问题中的代码示例所做的。
@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);
}
输出:
{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);
}
我有以下 for 循环,我想用一个简单的 Java 8 流语句替换它:
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++);
}
我基本上想要每个单词与其编号(在每个 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
列表中没有重复项,则上面的代码有效。
如果可能有重复的词,需要提供一个合并功能select 哪个索引应该存储在地图中(第一个或最后一个)
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
));
类似地,可以通过流式传输 words
和使用外部变量来增加索引来构建地图(可以使用 AtomicLong
和 getAndIncrement()
代替 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();}
,具体取决于您希望如何 合并 两个元素。
I basically want a sorted map (by insertion order) of each word to its number (which is incremented at each for loop by 1), but done simpler, if possible with Java 8 streams.
您可以使用以下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++);
}
比较简单。
一个略有不同的解决方案。 Integer::max
是合并函数,如果同一个词出现两次,则会调用该函数。在这种情况下,它会选择最后一个位置,因为这实际上是问题中的代码示例所做的。
@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);
}
输出:
{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);
}