[英]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.