3 回答
TA贡献1796条经验 获得超4个赞
Set.contains 有一个基于平等的精确定义:
更正式地说, true 当且仅当此集合包含一个元素 e 使得 (o==null ? e==null : o.equals(e))。
它会违反合同的方法,它使用除平等以外的任何方法。并且相等有一个精确的定义,即它必须是可传递的(除其他属性外)。使用容差的相等方法不是可传递的。
因此,没有办法Set.contains允许容差。
然而,这并不是说你永远不应该检查一个集合是否包含某个值的容差范围内的值——只是不要试图重载contains这样做的概念。
例如,您可以有一个采用 a NavigableSet(例如 a TreeSet)的subSet方法,并使用其方法:
static boolean containsApprox(NavigableSet<Double> set, double target, double eps) {
return !set.subSet(target - eps, true, target + eps, true).isEmpty();
}
这只是请求从target-eps到target+eps(包括true参数所指示的)运行的集合部分。如果这是非空的,则eps在target.
这显然是一个独立于标准的概念Set.contains,因此可以执行不共享相同属性的包含检查。
你不能subSet用 a做同样的把戏,HashMap因为它是一个无序映射 - 没有有效的方法来提取给定范围内的值。您将必须迭代整个集合,如Sun 的回答中所示,寻找匹配的值。
TA贡献1801条经验 获得超8个赞
可能您可以使用anyMatch,例如,根据后的前两位数字进行比较.:
Set<Double> set = Set.of(2.0, 5.0, 7.0);
Double compared = 2.0001d;
System.out.println(
set.stream().anyMatch(aDouble ->
Math.floor(aDouble * 100) / 100 == Math.floor(compared * 100) / 100
));
TA贡献1802条经验 获得超5个赞
我可以看到三个选项:
在将数字添加到集合之前先对数字进行四舍五入
编写一个
double
包装类并重新定义equals方法将 a
TreeSet
与自定义比较器一起使用
请注意,最后两个选项可能令人满意,也可能不令人满意,因为您填充集合的顺序会影响保留哪些元素。例如,如果您将精度设置为 0.01 并添加 0.01、0.011 和 0.02,则集合中将有两个元素(0.01 和 0.02)。如果您先添加 0.011,然后添加 0.01,然后添加 0.02,您将只有一个元素:0.011。我不知道这对您的用例是否有问题。
最后一个选项可能如下所示:
static Set<Double> setWithPrecision(double epsilon) {
return new TreeSet<> ((d1, d2) -> {
if (d1 <= d2 - epsilon) return -1;
if (d1 >= d2 + epsilon) return 1;
return 0;
});
}
使用示例:
Set<Double> set = setWithPrecision(0.01);
set.add(0d);
set.add(0.00001d);
set.add(0.01d);
set.add(0.02d);
System.out.println(set); // [0.0, 0.01, 0.02]
添加回答
举报