【问题标题】:How can I sort this ArrayList the way that I want?如何按照我想要的方式对这个 ArrayList 进行排序?
【发布时间】:2010-10-27 18:38:23
【问题描述】:

这是一个简单的 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 进行排序,如预期输出所示?

【问题讨论】:

  • 是的,它是在进行字符串比较而不是整数。
  • 尝试查找“自然顺序比较”sourcefrog.net/projects/natsort
  • 因为它的排序为字符串ASCII Table
  • 数字小于下划线,因此“11”小于“1_”。

标签: java sorting arraylist


【解决方案1】:

如上所述,您正在寻找实现自然排序的 Comparator 实现。 Jeff Atwood 前段时间写了一篇出色的 post on natural sorting - 非常值得一读。

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

【讨论】:

    【解决方案2】:

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

    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('_')));
        }
    });
    

    【讨论】:

    • 你就是那个男人。非常感谢。它工作得很好。我向你致敬:)
    • 只有一个警告:如果您遇到不符合模式 \​​d+_.* 的字符串,您可以预期这会引发异常。
    • 是的!我明白,但这是我的问题的快速解决方案。
    【解决方案3】:

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

    【讨论】:

    • 当问题只是关于为什么会发生这种情况时给出了这个答案。后来问题被编辑并以更具体的方式提出(如何解决问题)。因此,我在 nsayer 和其他人发表他们的答案之后添加了第二句话。
    【解决方案4】:

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

    注意 ArrayList 是如何按项目的 name 属性排序的。如果不添加 IComparable,那么在使用 sort 方法时会抛出错误。

    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;
            }
        }
    

    【讨论】:

    • items.Sort();本来很好,但这个问题是关于 Java 而不是 C# :)
    【解决方案5】:

    它正在进行字典比较。它比较每个字符串中的第一个字符对它们进行排序。然后它比较具有相同第一个字符的第二个字符串。当它将“_”字符与数字进行比较时,它的值大于任何单个数字字符,例如 8 > 7 和 a > 9。请记住,它是在进行字符比较而不是数字比较。

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

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

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

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

    【讨论】:

    • 这是“词典”,而不是“词典”。
    • 我自己更喜欢“asciibetical”。
    【解决方案6】:

    大家已经指出,解释是你的字符串是按字符串排序的,一个数字已经把你的注意力引向Natural Order字符串比较。我只想补充一点,自己编写比较器是一个很好的练习,也是一个练习测试驱动开发的好机会。我在 Code Camp 上用它来演示 TDD;幻灯片和代码是here

    【讨论】:

      【解决方案7】:

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

      Collections.sort(List list, Comparator c)  
      

      然后简单地实现一个比较器,它拆分字符串并首先根据数字排序,然后根据其余部分或您希望它排序。

      【讨论】:

        【解决方案8】:

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

        1 10 100 2 20 200

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

        001 002 010 020 100 200

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            【解决方案10】:

            字符串比较算法一次比较每个字符1 排在 2 之前。后面跟12都没关系。

            所以100 将排在2 之前。如果您不希望出现这种情况,则需要一个比较算法来处理这种情况。

            【讨论】:

              【解决方案11】:

              因为字符串是按字母顺序排序的,并且下划线字符位于数字字符之后。您必须提供一个实现“自然顺序”的比较器才能达到预期的结果。

              【讨论】:

                【解决方案12】:

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

                将指定的列表排序为 升序,根据 其元素的自然排序。

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

                【讨论】:

                  猜你喜欢
                  • 2018-02-11
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-11-24
                  • 1970-01-01
                  • 2015-06-16
                  • 2011-12-09
                  • 2016-02-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多