首页 > 解决方案 > 我们如何使用 map 从双精度数组中获取唯一元素‽

问题描述

我目前正在解决以下编程练习:查找唯一编号语句是:

有一个带有一些数字的数组。除了一个,所有数字都相等。试着找到它!

Kata.findUniq(new double[]{ 1, 1, 1, 2, 1, 1 }); // => 2 Kata.findUniq(new double[]{ 0, 0, 0.55, 0, 0 }); // => 0.55

保证数组包含 3 个以上的数字。

测试包含一些非常大的数组,因此请考虑性能。

首先我的想法是将所有元素的频率作为映射,然后返回频率值仅为 1 的键。

我写了以下内容:

import java.util.stream.*;

 public class Kata {
    public static double findUniq(double arr[]) {

      Map<Double, Long> frequencies = Arrays.stream(arr)
        .collect(Collectors.groupingBy(n -> n, Collectors.counting()));

      System.out.println("Map: "+map);

    }
}

所以它输出:

./src/main/java/Kata.java:8: error: method collect in interface DoubleStream cannot be applied to given types;
        .collect(Collectors.groupingBy(n -> n, Collectors.counting()));
        ^
  required: Supplier<R>,ObjDoubleConsumer<R>,BiConsumer<R,R>
  found: Collector<Object,CAP#1,Map<Object,Long>>
  reason: cannot infer type-variable(s) R
    (actual and formal argument lists differ in length)
  where R is a type-variable:
    R extends Object declared in method <R>collect(Supplier<R>,ObjDoubleConsumer<R>,BiConsumer<R,R>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
./src/main/java/Kata.java:10: error: cannot find symbol
      System.out.println("Map: "+map);
                                 ^
  symbol:   variable map
  location: class Kata
2 errors

我想解决这个问题的方法是理解:

required: Supplier<R>,ObjDoubleConsumer<R>,BiConsumer<R,R>
  found: Collector<Object,CAP#1,Map<Object,Long>>

我确实知道它期望:Supplier<R>,ObjDoubleConsumer<R>,BiConsumer<R,R>而且我正在写作:Collector<Object,CAP#1,Map<Object,Long>>但它是什么意思?我们怎样才能解决它?为什么会生成?

然后我尝试了第二种方法:使用 HashSet 获取所有不同的双精度数,然后删除不唯一的双精度数,并返回存储在 HashSet 中的唯一双精度数。

import java.util.*;
import java.util.stream.*;

 public class Kata {
    public static double findUniq(double arr[]) {
      System.out.println("\nOriginal array: "+Arrays.toString(arr));

      Set<Double> unique = new HashSet<Double>();
      double repeated = Double.MIN_VALUE;

      for(int i = 0; i < arr.length; i++){
        if(repeated != arr[i] && !unique.add(arr[i])){
          repeated = arr[i];
        }
      }
      unique.remove(repeated);
      System.out.println("Set: "+Arrays.toString(unique.toArray()));
      return (double)unique.toArray()[0];
    }
}

我的问题是,我们如何才能实现返回唯一元素,使用第一种方法,用地图计算频率,然后返回值为 1‽ 的键。

我也读过:

Java Hashmap:如何从值中获取键? 如何从数组中获取唯一项?

标签: javaarraysloopsunique

解决方案


发生编译器错误是因为Collector您使用的 s 不起作用-原始sDoubleStream的专用类型。你可以做的是把它变成第一个,然后应用:StreamdoubleDoubleStreamStream<Double>Collector

Map<Double, Long> frequencies = Arrays.stream(arr)
        .boxed() // this is the key method to call
        .collect(Collectors.groupingBy(n -> n, Collectors.counting()));

然后你需要找到值为 1 的 KVP,但地图并不是真的为此而设计的:

System.out.println("Map: "+ 
    frequencies.entrySet().stream()
        .filter(x -> x.getValue() == 1)
        .findFirst().get().getKey());

请注意,有比这更快的解决方案。请记住,只有一个双打是不同的!


推荐阅读