我怎样才能按照我想要的方式对这个ArrayList进行排序?

时间:2009-05-20 21:06:31

标签: java sorting arraylist

这是一个ArrayList的简单排序程序:

ArrayList<String> list = new ArrayList<String>();

list.add("1_Update");
list.add("11_Add");
list.add("12_Delete");
list.add("2_Create");

Collections.sort(list);
for (String str : list) {
  System.out.println(str.toString());
}

我期待这个节目的输出为:

1_Update
2_Create
11_Add
12_Delete

但是当我运行这个程序时,我得到的输出为:

11_Add
12_Delete
1_Update
2_Create

为什么会这样,如何让ArrayList按预期输出显示进行排序?

12 个答案:

答案 0 :(得分:70)

您可以编写自定义比较器:

Collections.sort(list, new Comparator<String>() {
    public int compare(String a, String b) {
        return Integer.signum(fixString(a) - fixString(b));
    }
    private int fixString(String in) {
        return Integer.parseInt(in.substring(0, in.indexOf('_')));
    }
});

答案 1 :(得分:8)

当您将此类数据排序为字符串时,它会比较字符本身,包括数字。例如,所有以“1”开头的字符串将一起结束。所以订单最终类似于......

1 10 100 2 20 200

排序“没有意识到”你正在为字符串的子集分配含义,例如字符串前面的可变长度数。将数字排序为字符串时,用尽可能多的零填充左侧以覆盖最大数字可能会有所帮助,但是当您不控制数据时,它并没有真正解决问题,如您的示例所示。在这种情况下,排序将是......

001 002 010 020 100 200

答案 2 :(得分:6)

它按文本(按字母顺序)排序,而不是数字。为了解决这个问题,您可以按照nsayer的回答中的建议实现自定义比较器。

答案 3 :(得分:3)

它正在进行字典比较。它比较每个字符串中的第一个字符排序。然后它将第二个字符串与相同的第一个字符进行比较。当它将'_'字符与数字进行比较时,它的值大于任何单个数字字符,就像8&gt; 7和a> 9.记住它正在进行字符比较而不是数字比较。

有多种方法可以实现自己的自定义排序路由,这可能比重命名脚本名称更好。

如果重命名脚本名称是一个选项,则可能允许使用其他脚本工具。一种格式可能是

01_create_table.sql
02_create_index.sql
11_assign_privileges.sql

通过将前两位数字保持为两个字符,字典比较将起作用。

答案 4 :(得分:2)

Collections.sort()方法的文档说:

  

将指定列表排序为   按照升序排列   其元素的自然排序。

对于字符串,这意味着您将按字母顺序获取列表。字符串11_assign_privileges.sql位于字符串1_create_table.sql之前,12_07_insert_static_data.sql位于1_create_table.sql等之前。因此程序正在按预期工作。

答案 5 :(得分:0)

要让Collection.sort()任意排序,您可以使用

Collections.sort(List list, Comparator c)  

然后简单地实现一个Comparator,它会拆分字符串并根据数字进行排序,然后根据数字进行排序,或者您希望它进行排序。

答案 6 :(得分:0)

每个人都已经指出,解释是你的字符串正在排序为字符串,并且一些数字已经引导你注意自然顺序字符串比较。我只想补充说,自己编写比较器是一个很好的练习,也是练习测试驱动开发的好机会。我用它在Code Camp演示TDD;幻灯片&amp;代码是here

答案 7 :(得分:0)

如上所述,您正在寻找实现自然排序的Comparator实现。杰夫阿特伍德不久前写了一篇很棒的post on natural sorting - 非常值得一读。

如果您正在寻找Java实现,我发现这个实现很有用: http://www.davekoelle.com/alphanum.html

答案 8 :(得分:0)

您可以添加IComparable接口,然后按特定属性排序。例如,如果你有一个商店的商品集合,你可能想要按价格或类别等对它们进行排序。如果你想按名称订购这里就是一个例子:

注意ArrayList是如何按项的name属性排序的。如果你没有添加IComparable,那么当你使用sort方法时,它会抛出一个错误。

enter image description here

static void Main(string[] args)
    {
        ArrayList items = new ArrayList();
        items.Add(new Item("book", 12.32));
        items.Add(new Item("cd", 16.32));
        items.Add(new Item("bed", 124.2));
        items.Add(new Item("TV", 12.32));

        items.Sort();

        foreach (Item temp in items)
            Console.WriteLine("Name:{0} Price:{1}", temp.name, temp.price);
        Console.Read();            
    }


    class Item: IComparable
    {
        public string name;
        public double price;

        public Item(string _name, double _price)
        {
            this.name = _name;
            this.price = _price;
        }

        public int CompareTo(object obj)
        {   
            //note that I use the name property I may use a different one
            int temp = this.name.CompareTo(((Item)obj).name);
            return temp;
        }
    }

答案 9 :(得分:0)

因为字符串按字母顺序排序,而下划线字符排在数字字符之后。您必须提供一个实施“自然顺序”的比较器来实现所需的结果。

答案 10 :(得分:0)

字符串比较算法一次比较每个字符1之前2排序。跟随12

并不重要

因此100会在2之前排序。如果您不想要这种行为,则需要一个处理这种情况的比较算法。

答案 11 :(得分:0)

正如其他人所说,默认情况下,元素将按字母顺序排序。解决方案是定义一个具体的java.util.Comparator类,并将其作为第二个参数传递给sort方法。你的比较器需要从字符串中解析出前导整数并进行比较。