IllegalStateException:Collectors.toMap()的“重复密钥”

时间:2019-05-21 03:04:59

标签: java java-8

  

参考问题:   Numbers which constitute the Maximum sum

我正在编写一个程序,该程序将打印构成最大和的元素。 我可以经历任何随机情况,但是当我的最大和为两组时,我的代码将失败。

我的代码:

class Ideone {
    public static void main(String[] args) throws java.lang.Exception {
        Scanner reader = new Scanner(System.in);
        int TestCases = reader.nextInt();
        reader.nextLine();
        String[] output = new String[TestCases];
        String sss = "";
        String ddd = "";

        for (int k = 0; k < TestCases; k++) {
            int noofELements = reader.nextInt();
            reader.nextLine();
            String[] al = reader.nextLine().split(" ");
            List<Integer> numbers = Arrays.stream(al).map(Integer::valueOf).collect(Collectors.toList());
            Ideone mm = new Ideone();
            String maxi = mm.maximumm(numbers, ddd);
            sss = sss.concat(maxi);

        }
        System.out.println(sss);

    }

    public String maximumm(List<Integer> numbers, String sss) {
        int toIndex = 3, fromIndex = 0;
        List<Integer> result = new ArrayList<>();
        while (toIndex < numbers.size()) {
            Map<Integer, Integer> map =
                IntStream.range(fromIndex, toIndex).mapToObj(i -> new AbstractMap.SimpleEntry<>(i, numbers.get(i)))
                    .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
            // find max of sublist
            int maxOfSub = numbers.subList(fromIndex, toIndex).stream().max(Integer::compareTo).get();
            //update indexes
            fromIndex = map.get(maxOfSub) + 2;
            toIndex += fromIndex;

            result.add(maxOfSub);
        }
        int lastMax = numbers.subList(fromIndex, numbers.size()).stream().max(Integer::compareTo).get();
        if (lastMax > 0) {
            result.add(lastMax);
        }
        result = result.stream().sorted(Integer::compareTo).collect(Collectors.toList());
        //System.out.println(result);
        sss = sss.concat(result.toString().replace(", ", "").replace("]", "").replace("[", ""));
        return sss;
        //  return result.stream().reduce(0,Integer::sum);
    }
}

例如,当我输入4 5 4 3时,不相邻元素的最大和为8,这将由4 45 3得出。

我的完整代码工作正常,只是我无法在最终结果中得到两个结果。

我的错误日志:

  

线程“主”中的异常java.lang.IllegalStateException:复制   按键0   java.util.stream.Collectors.lambda $ throwingMerger $ 0(Collectors.java:133)     在java.util.HashMap.merge(HashMap.java:1254)在   java.util.stream.Collectors.lambda $ toMap $ 58(Collectors.java:1320)在   java.util.stream.ReduceOps $ 3ReducingSink.accept(ReduceOps.java:169)     在java.util.stream.IntPipeline $ 4 $ 1.accept(IntPipeline.java:250)在   java.util.stream.Streams $ RangeIntSpliterator.forEachRemaining(Streams.java:110)     在java.util.Spliterator $ OfInt.forEachRemaining(Spliterator.java:693)     在   java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)     在   java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)     在   java.util.stream.ReduceOps $ ReduceOp.evaluateSequential(ReduceOps.java:708)     在   java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)     在   java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)     在Ideone.main(Ideone.java:27)的Ideone.maximumm(Ideone.java:47)

错误指向此行:result.add(maxOfSub);

任何帮助都会很好:)

3 个答案:

答案 0 :(得分:2)

此错误的原因是,您在调用<key>时重复了Stream.collect()。请记住,此方法对流元素执行可变的约简操作。因此,当您拨打电话时:

.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

在这里,您正在将<keys>对象的Map定义为<values>方法定义的Entry<index, values>的{​​{1}}。现在,当您在数据测试中拥有Stream.mapToObj()时,这意味着您正在尝试为数字4, 5, 4, 3创建两次<key>。因此,您得到了这个4

但是我该如何解决呢?

非常简单,只需在IllegalStateException调用中将Map对象的定义从<values, indexes>切换到<indexes, values>我该怎么做?好吧,只需将Stream.collect()替换为Map.Entry::getValue,反之亦然,就像这样:

Map.Entry::getKey

此外,通过使用.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 方法,可以得到更好的等效结果。此方法返回一个IntStream.boxed(),该元素由该流的元素组成,每个元素都装在Stream中。对我来说,这是将Integer对象转换为List对象的最佳方法,如下所示:

Map

请注意,我正在使用表达式Map<Integer, Integer> map = IntStream .range(fromIndex, toIndex) .boxed() .collect(Collectors.toMap(i -> i, i -> numbers.get(i) > 0 ? numbers.get(i) : 0)); 来分配i -> numbers.get(i) > 0 ? numbers.get(i) : 0对象的<values>您为什么这样做?因为我们需要跟踪删除负数,所以我将其替换为零。 Map方法是替代方法,但是Stream.filter()对象将不包含过滤后的元素。

但是,此修改将影响您更新索引的方式,因为现在映射值是Map而不是<values>,如以下行所示:

<indexes>

要解决此问题,您只需像下面这样从corespondent fromIndex = map.getOrDefault(maxOfSub, toIndex - 1) + 2; 获取<index>即可>

<value>

替代解决方案

现在,以上信息仅能解决fromIndex = IntStream .range(fromIndex, toIndex) .filter(i -> map.get(i).equals(maxOfSub)) .findFirst() .orElse(toIndex - 1) + 2; 。但是,我发现还有另一个错误。如果我使用此数字数组IllegalStateException,则非相邻数字的最大和应为1, 9, 1, 7, 7, 5, 4, 1, 6,但您的代码为[9 + 7 + 5 + 6] = 27。所以我试图在这里找到解决方案:

[9 + 7 + 6] = 22

答案 1 :(得分:0)

您正在尝试从具有重复值的映射构建反向映射,这会导致键重复。您必须避免这种情况。

类似的地图

{0: 4, 1: 5, 2: 4, 3: 3}

不能转换为

{4: 0, 5: 1, 4: 2, 3: 3}

因为map.get(4)会是什么?是4还是0?

错误发生在

// 1)
IntStream.range(fromIndex, toIndex)
    // 2)
    .mapToObj(i -> new AbstractMap.SimpleEntry<>(i, numbers.get(i)))
    // 3)
    .collect(Collectors.toMap(
                 Map.Entry::getValue, 
                 Map.Entry::getKey));
  • 1)首先创建一个整数范围流(0、1、2、3)
  • 2),然后创建SimpleEntry ((0: numbers[0]), (1: numbers[1]), (2: numbers[2]))
  • 3),然后尝试将其反转为地图:

    {数字[0]:0,数字[1]:1 ...}

答案 2 :(得分:0)

您的值中有些重复<keys>。看:

Map<Integer, Integer> map =
                IntStream.range(fromIndex, toIndex).mapToObj(i -> new AbstractMap.SimpleEntry<>(i, numbers.get(i)))
                    .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

如何解决

您交换了代码key-value中的Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey),所以出现了重复的错误。