简体   繁体   English

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

[英]How can I sort this ArrayList the way that I want?

Here is a simple sorting program of an 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());
}

I was expecting the output of this program as: 我期待这个程序的输出为:

1_Update
2_Create
11_Add
12_Delete

But when I run this program I am getting output as: 但是当我运行这个程序时,我得到输出为:

11_Add
12_Delete
1_Update
2_Create

Why is this and how do I get the ArrayList to sort as shown in the expected output? 为什么这样,如何让ArrayList按预期输出显示排序?

You could write a custom comparator: 你可以编写一个自定义比较器:

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

When you sort this type of data as a string, it is comparing the characters themselves, including the digits. 当您将此类数据排序为字符串时,它会比较字符本身,包括数字。 All of the string that begin with "1", for example, will end up together. 例如,所有以“1”开头的字符串将一起结束。 So the order ends up similar to this... 所以订单最终与此类似......

1 10 100 2 20 200 1 10 100 2 20 200

At no point does the sort "realize" that you are assigning meaning to subsets of the string, such as the variable length numbers at the front of the string. 在任何时候,排序都“实现”您正在为字符串的子集分配含义,例如字符串前面的可变长度数字。 When sorting numbers as strings, padding to the left with zeros as much as required to cover the largest number can help, but it does not really solve the problem when you don't control the data, as in your example. 将数字排序为字符串时,用尽可能多的零填充左边覆盖最大数字可能会有所帮助,但是当您不控制数据时,它并没有真正解决问题,如您的示例所示。 In that case, the sort would be... 在那种情况下,排序将是......

001 002 010 020 100 200 001 002 010 020 100 200

It is sorted as text (alphabetically), not as numbers. 它按文本(按字母顺序)排序,而不是数字。 To get around this you could implement a custom comparator as suggested in the answer by nsayer. 为了解决这个问题,您可以按照nsayer的回答中的建议实现自定义比较器。

It is doing a lexicographic comparison. 它正在进行词典比较。 It compares the first character in each string sorting them. 它比较每个字符串中的第一个字符排序。 It then compares the second string of those with the same first charater. 然后它将第二个字符串与相同的第一个字符进行比较。 When it compares the '_' character to a number, it is greater in value than any single number character just like 8 > 7 and a > 9. Remember it is doing a character comparison and not a numeric comparison. 当它将'_'字符与数字进行比较时,它的值大于任何单个数字字符,就像8> 7和a> 9.记住它正在进行字符比较而不是数字比较。

There are ways to implement your own custom sorting routing which may be better than renaming your script names. 有一些方法可以实现自己的自定义排序路由,这可能比重命名脚本名称更好。

If renaming your script names is an option, this may allow other script tools to be used. 如果重命名脚本名称是一个选项,这可能允许使用其他脚本工具。 One format may be 一种格式可能是

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

By keeping your first two digits to two characters, the lexicographic comparison will work. 通过将前两位数保持为两个字符,词典比较将起作用。

The Collections.sort() method's docs says: Collections.sort()方法的文档说:

Sorts the specified list into ascending order, according to the natural ordering of its elements. 根据元素的自然顺序,将指定列表按升序排序。

Which means for Strings that you are going to get the list in alphabetic order. 这意味着对于字符串,您将按字母顺序获取列表。 The String 11_assign_privileges.sql comes before the string 1_create_table.sql and 12_07_insert_static_data.sql comes before 1_create_table.sql etc. So the program is working as expected. 字符串11_assign_privileges.sql位于字符串1_create_table.sql之前,12_07_insert_static_data.sql位于1_create_table.sql之前。因此程序正在按预期工作。

You can add the IComparable interface and then sort by a specific property. 您可以添加IComparable接口,然后按特定属性进行排序。 If you have a collections of items of a store for example maybe you want to sort them by price or by category etc. If you want to order by name here is an example: 例如,如果你有一个商店的商品集合,你可能想要按价格或类别等对它们进行排序。如果你想按名称订购这里是一个例子:

note how the ArrayList is sorted by the name property of the items. 注意ArrayList是如何按项的name属性排序的。 If you do not add the IComparable then when you use the sort method it will throw an error. 如果您不添加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;
        }
    }

Because strings are sorted in a alphabetic ordering and the underscore character is after characters for numbers. 因为字符串按字母顺序排序,而下划线字符排在数字字符之后。 You have to provide a comparator implementing "Natural Order" to achieve desired result. 您必须提供一个实施“自然顺序”的比较器来实现所需的结果。

The string compare algorithm compare each character at a time. 字符串比较算法一次比较每个字符 1 sorts before 2 . 1排序前2 It doesn't matter that it is followed by a 1 or a 2 . 它跟随12并不重要。

So 100 would sort before 2 . 所以100会在2之前排序。 If you don't want this behavior, you need a compare algorithm that handles this case. 如果您不想要此行为,则需要一个处理此案例的比较算法。

As others have stated, the elements will be sorted alphabetically by default. 正如其他人所说,默认情况下,元素将按字母顺序排序。 The solution is define a concrete java.util.Comparator class and pass it as a second argument to the sort method. 解决方案是定义一个具体的java.util.Comparator类,并将其作为第二个参数传递给sort方法。 Your comparator will need to parse out the leading integers from the strings and compare them. 比较器需要从字符串中解析出前导整数并进行比较。

To have Collection.sort() sort arbitrarily you can use 要使Collection.sort()任意排序,您可以使用

Collections.sort(List list, Comparator c)  

Then simply implement a Comparator that splits the string and sorts first based on the number and then on the rest or however you want it to sort. 然后简单地实现一个比较器,它拆分字符串并首先根据数字进行排序,然后对其余部分进行排序,或者您希望它进行排序。

Everyone has already pointed out that the explanation is that your strings are sorting as strings, and a number have already directed your attention to Natural Order string comparison. 每个人都已经指出,解释是你的字符串排序为字符串,并且一些数字已经引导你注意自然顺序字符串比较。 I'll just add that it's a great exercise to write that comparator yourself, and a great opportunity to practice test-driven development. 我只想补充说,自己编写比较器是一个很好的练习,也是练习测试驱动开发的好机会。 I've used it to demonstrate TDD at Code Camp; 我用它在Code Camp演示TDD; slides & code are here . 幻灯片和代码在这里

As stated above, you are looking for a Comparator implementation that implements a natural sort. 如上所述,您正在寻找实现自然排序的Comparator实现。 Jeff Atwood wrote an excellent post on natural sorting some time ago - it's well worth a read. 杰夫阿特伍德不久前写了一篇关于自然分类的优秀文章 - 非常值得一读。

If you're looking for a Java implementation I have found this one to be useful: http://www.davekoelle.com/alphanum.html 如果您正在寻找Java实现,我发现这个实现很有用: http//www.davekoelle.com/alphanum.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM