Как я могу отсортировать этот ArrayList так, как я хочу? - PullRequest
36 голосов
/ 21 мая 2009

Вот простая программа сортировки 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 ]

70 голосов
/ 21 мая 2009

Вы можете написать собственный компаратор:

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('_')));
    }
});
8 голосов
/ 21 мая 2009

Когда вы сортируете этот тип данных в виде строки, он сравнивает сами символы, включая цифры. Например, все строки, начинающиеся с «1», будут заканчиваться вместе. Таким образом, порядок в конечном итоге похож на этот ...

1 10 100 2 20 200

Ни в коем случае сортировка не "понимает", что вы присваиваете значение подмножествам строки, таким как числа переменной длины в начале строки. При сортировке чисел в виде строк может помочь заполнение нулями нуля до того числа, которое требуется для покрытия наибольшего числа, но это не решает проблему, когда вы не управляете данными, как в вашем примере. В этом случае сортировка будет ...

001 002 010 020 100 200

6 голосов
/ 21 мая 2009

Сортируется как текст (в алфавитном порядке), а не как числа. Чтобы обойти это, вы можете реализовать собственный компаратор, как предложено в ответе nsayer.

3 голосов
/ 21 мая 2009

Лексикографическое сравнение. Он сравнивает первый символ в каждой строке, сортируя их. Затем он сравнивает вторую строку из тех же первых символов. Когда он сравнивает символ '_' с числом, он больше по значению, чем любой отдельный символ числа, например, 8> 7 и a> 9. Помните, что выполняется сравнение символов, а не числовое сравнение.

Есть способы реализовать собственную настраиваемую маршрутизацию сортировки, которая может быть лучше, чем переименование имен ваших скриптов.

Если переименование имен ваших скриптов является опцией, это может позволить использовать другие инструменты скрипта. Один формат может быть

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

Если ваши первые две цифры состоят из двух символов, будет работать лексикографическое сравнение.

2 голосов
/ 21 мая 2009

В документации к методу Collections.sort () написано:

Сортирует указанный список в в порядке возрастания, в соответствии с естественное упорядочение его элементов.

Что означает для строк, что вы собираетесь получить список в алфавитном порядке. String 11_assign_privileges.sql предшествует строке 1_create_table.sql и 12_07_insert_static_data.sql предшествует 1_create_table.sql и т. Д. Таким образом, программа работает должным образом.

0 голосов
/ 12 марта 2011

Вы можете добавить интерфейс IComparable, а затем отсортировать по определенному свойству. Например, если у вас есть коллекции товаров в магазине, возможно, вы хотите отсортировать их по цене, по категории и т. Д. Если вы хотите сделать заказ по названию, вот пример:

обратите внимание, как ArrayList сортируется по свойству name элементов. Если вы не добавите IComparable, то при использовании метода сортировки будет выдано сообщение об ошибке.

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;
        }
    }
0 голосов
/ 21 мая 2009

Как указано выше, вы ищете реализацию Comparator, которая реализует естественную сортировку. Джефф Этвуд некоторое время назад написал отличный пост о естественной сортировке - его стоит прочитать.

Если вы ищете реализацию Java, я нашел это полезным: http://www.davekoelle.com/alphanum.html

0 голосов
/ 21 мая 2009

Все уже указали, что объяснение состоит в том, что ваши строки сортируются как строки, и число уже направило ваше внимание на сравнение строк в естественном порядке. Я просто добавлю, что это отличное упражнение, чтобы написать этот компаратор самостоятельно, и отличная возможность попрактиковаться в разработке на основе тестов. Я использовал его для демонстрации TDD в Code Camp; слайды и код здесь .

0 голосов
/ 21 мая 2009

Для произвольной сортировки Collection.sort () вы можете использовать

Collections.sort(List list, Comparator c)  

Затем просто реализуйте Comparator, который разбивает строку и сортирует сначала по числу, а затем по остальным или как вы хотите его отсортировать.

0 голосов
/ 21 мая 2009

Как уже говорили другие, элементы будут отсортированы по алфавиту по умолчанию. Решение - определить конкретный класс java.util.Comparator и передать его в качестве второго аргумента методу сортировки. Ваш компаратор должен будет выделить ведущие целые числа из строк и сравнить их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...