如何对 Number 类型的 ArrayList 进行排序

How to sort an ArrayList of type Number

提问人:Diavel 提问时间:9/10/2023 最后编辑:Diavel 更新时间:9/11/2023 访问量:141

问:

/* Here is a method to sort an array list
 * if the array list type is Integer ect this runs just fine
 * But errors on Number
 */ 

public static void sort(ArrayList<Number> list){
    Collections.sort(list);
    for(Number N: list)
        System.out.printf("[%d]",N);
    System.out.println();
}

该代码适用于除 Number 以外的任何类型的数组列表。但是我需要使用.Number

Java ArrayList 数字格式化

评论

2赞 Slaw 9/10/2023
使用重载(或仅 )并提供适当比较对象的重载。你如何确定什么是“适当的比较”取决于你,可以从其他限制中推断出来,或者你需要向你的教授要求澄清。sort(List,Comparator)List#sort(Comparator)Comparator<Number>Number
5赞 Jim Garrison 9/10/2023
Number不实现,您必须编写一个可以确定实际子类型并调用相应比较器的比较器。Comparable
1赞 g00se 9/10/2023
粗糙且准备好,但您可以尝试list.stream().mapToDouble(Number::doubleValue).sorted().forEach(System.out::println);
0赞 Jim Garrison 9/24/2023
这是一个微妙而又相当困难的问题。您必须同时考虑所有可能表示的范围和精度,并将每个表示作为不同的情况进行处理。没有一种类型可以包含 Number 的所有子类型中的所有可能值,同时保持精度。如果数组包含混合的子类型,事情就会变得更加复杂。我不认为下面的任何答案都解决了这个问题。NumberNumber

答:

-1赞 Reilas 9/10/2023 #1

"...该代码适用于除 Number 以外的任何类型的数组列表。但我被要求使用数字

使用 BigDecimal 类进行比较。

list.sort(Comparator.comparing(e -> new BigDecimal(String.valueOf(e))));
public static void sort(ArrayList<Number> list){
    list.sort(Comparator.comparing(e -> new BigDecimal(String.valueOf(e))));
    for(Number N: list)
        System.out.printf("[%s]",N);
    System.out.println();
}

此外,还需要将 printf 说明符调整为 ,否则将收到 IllegalFormatConversionException%s

下面是一个包含一些随机 Number 对象的示例。

ArrayList<Number> list = new ArrayList<>();
list.add(4);
list.add(3f);
list.add(2l);
list.add(1d);
System.out.println(list);
sort(list);

输出

[4, 3.0, 2, 1.0]
[1.0][2][3.0][4]

评论

0赞 M. Justin 9/11/2023
这是假设每个对象的字符串值是 a 的有效表示,并且可以使用 .对于所有内置数字类型来说,这可能是正确的,严格来说,它不能保证对于自定义类型是正确的。NumberBigDecimalnew BigDecimal(value)Number
0赞 M. Justin 9/12/2023
实际上,即使使用内置类型,也存在无法使用构造函数转换为的值。例如,、 和 。将这些值中的任何一个与此比较器一起使用都将导致被抛出。NumberBigDecimalBigDecimal(String)Double.POSITIVE_INFINITYDouble.NEGATIVE_INFINITYDouble.NaNNumberFormatException
0赞 Reilas 9/13/2023
@M.贾斯汀,你应该写一个答案。
1赞 Diavel 9/10/2023 #2

为了感谢 Jim Garrison,Number 不是 Comparable 的,因此需要为 Number 数据类型定义 Comparator。这可以这样完成。

static Comparator<Number> NumberComparator = new Comparator<Number>(){

    public int compare(Number n1, Number n2) {

        BigDecimal N1,N2;
        N1 = new BigDecimal(String.valueOf(n1));
        N2 = new BigDecimal(String.valueOf(n2));
        return N1.compareTo(N2);

    } 
};

感谢大家让我走上正确的道路,并在此过程中教我一些技巧。

评论

2赞 Basil Bourque 9/10/2023
您需要使用而不是 .第一个是 64 位,第二个是 32 位,因此任何现有的 or 数字都不适合 .doublefloatdoubleDoublefloat
1赞 g00se 9/10/2023
else if(n1.floatValue()==n2.floatValue())这里有几件事。如果你想“假设浮点”,最好像我一样做,并假设它具有更高的精度。其次,您应该避免检查浮点值是否绝对相等,因为精度问题可能会产生意想不到的结果,无论如何,f.p.值已经有s了。我的注释代码可以执行您现在正在做的事情,但没有问题doubleComparator
4赞 Basil Bourque 9/10/2023
请注意,这种方法无法正确处理对象(两者都是)。这些对象可能包含超过 64 位容量的数字。BigDecimalBigIntegerNumberdouble
1赞 g00se 9/10/2023
@BasilBourque当然是正确的,所以你可以用类似的方式使用BigDecimal
4赞 Bohemian 9/10/2023
不要重新发明轮子:或者只是return Double.compare(n1.doubleValue(), n2.doubleValue());return Comparator.comparing(Number::doubleValue);
0赞 Oleg Cherednik 9/10/2023 #3

您所需要的只是正确比较值。为此,您应该使用 .doubleDouble.compare()

但是可以更大,例如,所以一般来说,最好将每个数字转换为并进行比较。NumberBigDecimalBigDecimal

请记住,这不是有效的解决方案。

public static void sort(List<Number> list) {
    list.sort(Comparator.comparing(one -> new BigDecimal(one.toString())));
    
    for (Number N : list)
        System.out.printf("[%s]", N);
    
    System.out.println();
}