对一个包含数字字符串的ArrayList进行排序

7
什么是最快的方法来对包含数字的 ArrayList<String>(以升序或降序方式)进行排序,例如:{ "12", "3.5", "188", "33.03" } ? Collections 是否有内置方法可供使用?目前,我正在将 ArrayList 的内容复制到 ArrayList<Double> 中,然后使用 Collections.Sort() 方法,最后再将其放回初始数组。是否有更快的方法?

你可以实现自己的比较器,但不确定是否更快。 - sp00m
5
为什么你想把数字作为字符串插入到一个ArrayList中? - George Thomas
@GeorgeThomas 长话短说:维护别人的代码。 - astralmaster
2
@GeorgeThomas 我同意,如果是我,我会把它们全部变成双精度。 - DreadHeadedDeveloper
请查看此答案这里。它适用于所有类型的变量。 - Pedro Loureiro
显示剩余2条评论
6个回答

9

如果您使用Java 8,可以使用Comparator.comparing(Double::parseDouble)快速创建一个比较器来使用parseDouble。这将(见下文)为每个条目仅调用函数一次,而不是为每个对调用一次。

List<String> list = Arrays.asList( "12", "3.5", "188", "33.03" );
list.sort(Comparator.comparing(Double::parseDouble));
System.out.println(list);

输出:

[3.5, 12, 33.03, 188]
< p >< em >更新: 嗯,我原本以为这个会像Python中使用< code >key函数一样,对于每个元素只调用一次比较函数,但是在快速测试一个计数器递增的函数后,发现该函数与旧式“pair”比较器一样经常被调用。尽管如此,代码长度仍然有所缩短...< /p >

谢谢。尽管写的代码少,但我使用Java 7,并且据我所知,在版本7中,List没有sort()方法,是吗?有什么解决办法吗? - astralmaster
你有两种解决方案,就像在旧版Java中一样。要么创建一个比较器,就像上面的例子一样,要么让所有的集合对象实现Comparable接口,然后使用Collections.sort() :) 所以不,List没有sort方法:) 为什么呢?因为它是一个接口,有时候列表不需要被索引。 - Beri
@Ben 在Java 8中,List有一个sort方法 - tobias_k

7

您需要实现自己的比较器,并在列表上使用它。您必须使用BigDecimal,因为存在精度丢失的问题。如果您的数字非常小,则可以使用double。

class MyComparator implements Comparator<String, String> {

    public int compare(String o1, String o2){
        return new BigDecimal(o1).compareTo(new BigDecimal(o2));
    }

}
...
Collections.sort(list, new MyComparator());

最佳的Java 1.7解决方案!除非您知道值具有有限精度,否则可以使用Double.parseDouble()代替BigDecimal - Mark Jeronimus

4

尝试以下代码:

String test[] = {"12", "3.5", "188", "33.03"};
double numbers[] = new double[test.length];
for (int i = 0; i < test.length; i++) {
     numbers[i] = Double.parseDouble(test[i]);
}
Arrays.sort(numbers);
for (double i : numbers) {
     System.out.println(i);
}

输出:

3.5
12.0
33.03
188.0

1
这只是作者的做法,我没有踩反对票。 - Marco
基本上我所做的就是这样,但可能有更快的方法。 - astralmaster
你可以使用比较器,但我认为这是更快的方法。还有,为什么会有人踩呢? - Darshan Lila
个人而言,我不会在这里使用Float,因为可能会出现精度丢失的情况(当然这取决于输入值),但原则上这应该是可以的。 - blalasaadri
是的,floats可以改为double - Darshan Lila
显示剩余2条评论

4

我认为你目前的方法可能是可以的,我建议不要使用自定义Comparator,因为这样会导致同一个字符串被转换成数字多次(每次排序算法想要比较2个值时),而不是像现在一样只转换一次。


2
OP的方法是否存在风险,当原始元素为“0.1”时,在列表中最终得到“0.0999999999123”? - arne.b
关于多次转换的问题是一个好问题;一种解决方案可能是将转换后的值保存到映射中,然后进行检查。然而,哪种解决方案更快则是完全不同的问题... - blalasaadri

1
你可以在 List<String> 上使用 Collections.sort(),因为 String 是 Comparable,但是这种比较可能不会得到正确的结果。
另外,你可以定义自己的 Comparator,并将其传递给 Collections.sort()

1
你可以尝试使用sortedset接口,在输入数据时实现有序数据。最好实现自己的比较器,这样会更加有益。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接