【问题标题】:Remove duplicate numbers in Java 8 and get the sum删除 Java 8 中的重复数字并得到总和
【发布时间】:2018-02-20 08:45:43
【问题描述】:

我正在尝试删除 java 8 中的重复数字,包括引用数。例如,我有一个数组,其值类似于 (2,3,2,5)

所有数字 2 都应该被删除,而数字应该是 3 和 5。 所以预期的总和是 8。但是在我下面的代码中,它仍然得到 2。它确实删除了重复的数字,但仍然保留了数字参考。

这是我的代码。

List<Integer> clearedNumbers = numbers.stream().distinct().collect(Collectors.toList());
    int sum = clearedNumbers.stream().mapToInt(Integer::intValue).sum();

我得到的总和是 10 而不是 8。

【问题讨论】:

  • 您需要创建一个频率直方图,然后将频率为 1 的直方图相加
  • 使用Set,第一行更容易阅读。
  • 您得到的总和是正确的,因为它删除了重复项并执行了求和运算,您想要的是删除频率大于一的所有数字并执行求和运算。
  • distinct 显然会保持 one 2

标签: java arraylist lambda


【解决方案1】:

我会收集每个数字的计数,并且只计算单数:

 System.out.println(
         Stream.of(2,3,2,5)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                .entrySet()
                .stream()
                .filter(e -> e.getValue() == 1)
                .mapToInt(Map.Entry::getKey)
                .sum());

输出 8

【讨论】:

【解决方案2】:

您可以做得更聪明一点...(只要您有重复,只需通过 combiner 将其映射到 zero):

int result = Stream.of(2, 3, 2, 5)
            .collect(Collectors.collectingAndThen(
                    Collectors.toMap(
                            Function.identity(),
                            Function.identity(),
                            (x, y) -> 0),
                    map -> map.values().stream().mapToInt(Integer::intValue).sum()))

【讨论】:

  • 嗨尤金!这确实更聪明。但是 IMO 没有表达力,我的意思是意图不明确,您需要一些高级理解才能抓住这一点。
  • @FedericoPeraltaSchaffner 当你说“高级”时,我感觉自己聪明多了))
  • 嗯,advanced 是相对的。你明白我的意思,我还是赞成,因为你的答案是正确和有效的,而接受的答案和大多数其他答案是O(n^2),因为他们在Stream.filter 或@ 中使用Collections.frequencyList.contains 987654328@ 循环。不过,你的答案不是 Holger-advanced ;)
  • @FedericoPeraltaSchaffner 甚至没有关闭...同意。
【解决方案3】:

您得到的总和是正确的,因为它删除了重复项并执行了求和运算,您想要的是删除频率大于一的所有数字并执行求和运算。试试这个。

List<Integer> numbers = new ArrayList<>();
    numbers.add(2);
    numbers.add(3);
    numbers.add(2);
    numbers.add(5);

    List<Integer> clearedNumbers = numbers.stream().filter(num -> {
        return Collections.frequency(numbers, num) == 1;
    }).collect(Collectors.toList());
    int sum = clearedNumbers.stream().mapToInt(Integer::intValue).sum();
    System.out.println(sum);

【讨论】:

  • @OlaTorres 您可能选择了性能最差的答案,显然这是您的选择。
  • 请不要在过滤器中使用Collections.frequency,因为这会产生O(n^2) 的复杂性。
  • @Eugene 哦......对此感到抱歉......你对我如何在不使用频率的情况下实现结果有什么建议吗?提前致谢。
  • @OlaTorres 你没有什么好遗憾的,你可以选择接受你想要的任何答案,并注意这个答案是正确,它慢。而且我在这里也有点偏见,因为我也提供了答案...stackoverflow.com/a/48883475/1059372
【解决方案4】:

为什么不应用简单的方法来创建另一个没有当前元素的数组列表并进行比较。如果比较返回 false,则添加它们。看看下面的代码 sn -p :

public static void main(String[] args) {
        List<Integer> a = new ArrayList<Integer>();
        List<Integer> b = new ArrayList<Integer>();
        a.add(2);
        a.add(2);
        a.add(3);
        a.add(5);
        int sum = 0;
        for(int i=0; i < a.size(); i++) {
            b.clear();
            for(int j = 0; j < a.size(); j++) {
                if(j != i) 
                    b.add(a.get(j));
            }
            if(! b.contains(a.get(i)))
                sum = sum + a.get(i);
        }
        System.out.println(sum);
    }

它可以给出想要的结果。

【讨论】:

  • 请不要在 for 循环中使用 List.contains,因为这会产生 O(n^2) 复杂性。
【解决方案5】:

使用 Collections.Frequency API,

 System.out.println(numbers.stream()
                .filter(i -> Collections.frequency(numbers, i)==1)
                .mapToInt(Integer::intValue)
                .sum());

【讨论】:

  • 你要迭代多少次才能得到每个元素的频率,你怎么看?
  • 请不要在过滤器中使用Collections.frequency,因为这会产生O(n^2) 的复杂性。
  • @FedericoPeraltaSchaffner 是的,我同意
猜你喜欢
  • 2023-03-21
  • 2015-12-27
  • 2015-03-13
  • 1970-01-01
  • 1970-01-01
  • 2022-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多