[英]How can I sort this ArrayList the way that I want?
這是一個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按預期輸出顯示排序?
你可以編寫一個自定義比較器:
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”開頭的字符串將一起結束。 所以訂單最終與此類似......
1 10 100 2 20 200
在任何時候,排序都“實現”您正在為字符串的子集分配含義,例如字符串前面的可變長度數字。 將數字排序為字符串時,用盡可能多的零填充左邊覆蓋最大數字可能會有所幫助,但是當您不控制數據時,它並沒有真正解決問題,如您的示例所示。 在那種情況下,排序將是......
001 002 010 020 100 200
它按文本(按字母順序)排序,而不是數字。 為了解決這個問題,您可以按照nsayer的回答中的建議實現自定義比較器。
它正在進行詞典比較。 它比較每個字符串中的第一個字符排序。 然后它將第二個字符串與相同的第一個字符進行比較。 當它將'_'字符與數字進行比較時,它的值大於任何單個數字字符,就像8> 7和a> 9.記住它正在進行字符比較而不是數字比較。
有一些方法可以實現自己的自定義排序路由,這可能比重命名腳本名稱更好。
如果重命名腳本名稱是一個選項,這可能允許使用其他腳本工具。 一種格式可能是
01_create_table.sql 02_create_index.sql 11_assign_privileges.sql
通過將前兩位數保持為兩個字符,詞典比較將起作用。
Collections.sort()方法的文檔說:
根據元素的自然順序,將指定列表按升序排序。
這意味着對於字符串,您將按字母順序獲取列表。 字符串11_assign_privileges.sql位於字符串1_create_table.sql之前,12_07_insert_static_data.sql位於1_create_table.sql之前。因此程序正在按預期工作。
您可以添加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;
}
}
因為字符串按字母順序排序,而下划線字符排在數字字符之后。 您必須提供一個實施“自然順序”的比較器來實現所需的結果。
字符串比較算法一次比較每個字符 。 1
排序前2
。 它跟隨1
或2
並不重要。
所以100
會在2
之前排序。 如果您不想要此行為,則需要一個處理此案例的比較算法。
正如其他人所說,默認情況下,元素將按字母順序排序。 解決方案是定義一個具體的java.util.Comparator類,並將其作為第二個參數傳遞給sort方法。 比較器需要從字符串中解析出前導整數並進行比較。
要使Collection.sort()任意排序,您可以使用
Collections.sort(List list, Comparator c)
然后簡單地實現一個比較器,它拆分字符串並首先根據數字進行排序,然后對其余部分進行排序,或者您希望它進行排序。
每個人都已經指出,解釋是你的字符串排序為字符串,並且一些數字已經引導你注意自然順序字符串比較。 我只想補充說,自己編寫比較器是一個很好的練習,也是練習測試驅動開發的好機會。 我用它在Code Camp演示TDD; 幻燈片和代碼在這里 。
如上所述,您正在尋找實現自然排序的Comparator實現。 傑夫阿特伍德不久前寫了一篇關於自然分類的優秀文章 - 非常值得一讀。
如果您正在尋找Java實現,我發現這個實現很有用: http : //www.davekoelle.com/alphanum.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.