Java流将列表中的元素映射到数字

Java流将列表中的元素映射到数字,java,collections,java-8,java-stream,Java,Collections,Java 8,Java Stream,我将int[]转换为列表。手头的任务是将集合的每个元素映射为0。所以我想把这个列表转换成一个集合,然后映射到0。 所以对于集合1,3,7,4,8,它应该是:1,0,3,0,7,0,4,0,8,0。为了实现这一点,我尝试了: Map<Integer, Integer> map = Arrays.stream(elements) .boxed() .collect(Collectors.toMap(x -> x, x -> 0)); 但在尝试此操作时,我遇到

我将int[]转换为列表。手头的任务是将集合的每个元素映射为0。所以我想把这个列表转换成一个集合,然后映射到0。 所以对于集合1,3,7,4,8,它应该是:1,0,3,0,7,0,4,0,8,0。为了实现这一点,我尝试了:

Map<Integer, Integer> map = Arrays.stream(elements)
    .boxed()
    .collect(Collectors.toMap(x -> x, x -> 0));
但在尝试此操作时,我遇到了以下错误:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 0
    at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
    at java.util.HashMap.merge(HashMap.java:1254)
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.util.stream.IntPipeline$4$1.accept(IntPipeline.java:250)
    at java.util.Spliterators$IntArraySpliterator.forEachRemaining(Spliterators.java:1032)
    at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at DeleteElementsByOccurence.main(DeleteElementsByOccurence.java:18)                  <-- Refers to the Collectors.toMap line
我知道这在Scala中非常简单,但我无法理解Java中的逻辑

元素似乎包含重复项。为了解决这个问题,您可以向toMap提供第三个参数,以说明当存在重复项时您想要做什么

x和y是对应于两个重复键的值,您可以决定该键的新值。因为在这种情况下所有的值都是0,所以没有太多的选择,是吗


实际上,您不需要首先将数组转换为集合,因为第三个参数合并函数会自动处理重复项。

如果列表包含重复项,则映射将引发异常。您可以使用distinct删除重复的密钥

int[] a = {1,3,7,4,4,8}; // 4 is duplicated

Map<Integer, Integer> map = Arrays.stream(a)
    .boxed()
    .distinct()   // added
    .collect(Collectors.toMap(x -> x, x -> 0));
或者,传递一个合并函数

Map<Integer, Integer> map = Arrays.stream(a)
    .boxed()
    .collect(Collectors.toMap(x -> x, x -> 0, (x, y) -> x));

同样正确、相同的合并函数:x,y->y,x,y->0

它实际上是一个集合吗?您的代码暗示了一个元素数组,而这不是一个集合。检查数组中是否有重复的元素。糟糕,这是一个列表。如果列表中有重复的数字,该怎么办?是[1,1,2]->[1,0,1,0,2,0]还是[1,1,2]->[1,0,2,0]?如果您有一个列表,您应该不能使用Arrays.stream。你真的有一个int[]?@Sparker0i,那么它是.distinct,或者先创建一个集合,然后流式生成集合。大多数可行的方法已经有了答案。请注意,.distinct在引擎盖下也有一个集合,而带有三个lambda的toMap不会创建一个集合,并且最终仍能如您所期望的那样工作。此解决方案略优于.distinct one,因为它不会在引擎盖下分配一个集合来跟踪所看到的元素,因此,只需少一点对象分配和设置查找。@M.Prokhorov您的意思是稍微快一点。快一点!=更好。@Michael,不仅速度更快,而且中间使用的内存更少。包含集合的解决方案更好,因为它在逻辑上更一致。合并lambda从技术上讲是一个骗局。关于误导性的异常信息,我们已经在
Map<Integer, Integer> map = Arrays.stream(a)
    .boxed()
    .collect(Collectors.toMap(x -> x, x -> 0, (x, y) -> x));