[英]How to sort an ArrayList<String> using Comparator?
Hey guys I'm trying to make a scoreboard for my game and therefor I need to sort it. 大家好,我想为我的比赛做一个记分牌,因此我需要对它进行排序。 My input is DATE;LEVEL;SCORE and I want to sort it by the highest score, if it's equal by the highest level and if it's equal by the date. 我的输入是DATE; LEVEL; SCORE,我想按最高分对它进行排序,如果它与最高级别相等,并且与日期相等。
My ArrayList: 我的ArrayList:
ArrayList<String> test = new ArrayList<>();
test.add("16.06.2018;1;10");
test.add("16.06.2018;1;2");
test.add("16.06.2018;1;5");
test.add("16.06.2018;1;1");
test.add("16.06.2018;1;3");
test.add("16.06.2018;2;3");
test.add("15.06.2018;1;3");
test.add("17.06.2018;1;3");
should be sorted 应该排序
[16.06.2018;1;10, 16.06.2018;1;5, 16.06.2018;2;3, 15.06.2018;1;3, 16.06.2018;1;3, 17.06.2018;1;3, 16.06.2018;1;2, 16.06.2018;1;1];
but I'm getting 但我越来越
[16.06.2018;1;5, 16.06.2018;2;3, 15.06.2018;1;3, 16.06.2018;1;3, 17.06.2018;1;3, 16.06.2018;1;2, 16.06.2018;1;10, 16.06.2018;1;1]
My code: 我的代码:
Collections.sort(test, new Comparator<String>() {
@Override
public int compare(String A, String B) {
String[] tmp = A.split(";");
String[] tmp2 = B.split(";");
if (tmp[2].equals(tmp2[2])) {
if (tmp[1].equals(tmp2[1])) {
return compareDate(tmp[0], tmp2[0]);
} else {
return tmp2[1].compareTo(tmp[1]);
}
} else {
return tmp2[2].compareTo(tmp[2]);
}
}
//compares 2 dates
private int compareDate(String A, String B) {
String[] tmp = A.split("\\.");
String[] tmp2 = B.split("\\.");
if (tmp[2].equals(tmp2[2])) {
if (tmp[1].equals(tmp2[1])) {
return tmp[0].compareTo(tmp2[0]);
} else {
return tmp[1].compareTo(tmp2[1]);
}
} else {
return tmp[2].compareTo(tmp2[2]);
}
}
});
You're using a string-based lexical comparison which treats "5"
as being greater than "10"
(because the character '5'
comes after '1'
in the Unicode table). 您正在使用基于字符串的词法比较,该比较将"5"
视为大于"10"
(因为字符'5'
'1'
在Unicode表中位于'1'
之后)。
Instead you should use a numerical comparison. 相反,您应该使用数值比较。 Convert the strings to integers and compare them with Integer.compare
or similar: 将字符串转换为整数,然后将它们与Integer.compare
或类似的字符串进行比较:
Instead of this: 代替这个:
return tmp2[2].compareTo(tmp[2]);
You can do this: 你可以这样做:
return Integer.compare(
Integer.parseInt(tmp2[2]),
Integer.parseInt(tmp[2])
);
If you are using Java 8, I would like to create an Object from that String so you can compare it easily : 如果您使用的是Java 8,我想从该String创建一个Object,以便可以轻松比较它:
test.stream()
.map(c -> {
String[] tmp = c.split(";");
MyObject obj = new MyObject(
LocalDate.parse(tmp[0], DateTimeFormatter.ofPattern("dd.MM.yyyy")),
Integer.valueOf(tmp[1]), Integer.valueOf(tmp[2])
);
return obj;
}).sorted(
Comparator.comparing(MyObject::getDate)
.thenComparing(MyObject::getLevel)
.thenComparing(MyObject::getScore));
With this Object : 有了这个对象:
class MyObject {
private LocalDate date;
private Integer level;
private Integer score;
public MyObject(LocalDate date, Integer level1, Integer score) {
this.date = date;
this.level = level;
this.score= score;
}
public MyObject() {
}
//getter setter
}
Or without an Object : 或没有对象:
test.stream().map(c -> c.split(";")).sorted(
Comparator.comparing(a -> LocalDate.parse(((String[]) a)[0], DateTimeFormatter.ofPattern("dd.MM.yyyy")))
.thenComparing(a -> Integer.valueOf(((String[]) a)[1]))
.thenComparing(a -> Integer.valueOf(((String[]) a)[2])));
Note : You can put them in the order you want so you will get the expected result 注意:您可以按照需要的顺序排列它们,以便获得预期的结果
I like the approach from @YCF_L and how @jspcal gets right to the point. 我喜欢@YCF_L的方法以及@jspcal如何正确处理问题。 I would usually break it up into reusable components like this. 我通常将其分解成这样的可重用组件。
public static void sort(List<String> data) {
Collections.sort(data, new DataComparator());
}
private static class DataComparator implements Comparator<String>
{
@Override
public int compare(String str1, String str2) {
DataObject data1 = DataObject.valueOf(str1);
DataObject data2 = DataObject.valueOf(str2);
return data1.compareTo(data2);
}
}
private static class DataObject implements Comparable<DataObject>
{
private static final Map<String,DataObject> valuesCache = new HashMap<String,DataObject>();
private LocalDate date;
private int value1;
private int value2;
/**
* Parse the "date;value1;value2" String into an Object.
* @param value the string
* @throws ParseException if the date is invalid
*/
public DataObject(String value) {
String[] values = value.split(";");
this.date = LocalDate.parse(values[0], DateTimeFormatter.ofPattern("dd.MM.yyyy"));
this.value1 = Integer.valueOf(values[1]);
this.value2 = Integer.valueOf(values[2]);
}
/**
* Parse the String into an object.
* @param str the string
* @return the data object
*/
public static DataObject valueOf(String str) {
DataObject data = valuesCache.get(str);
if (data == null) {
data = new DataObject(str);
valuesCache.put(str, data);
}
return data;
}
/**
* Compare this DataObject to the other DataObject.
*/
@Override
public int compareTo(DataObject other) {
int cmp = 0;
if (this != other) {
// first compare the value2 integers
// sort descending (higher first) by multiplying by -1
cmp = -1 * Integer.compare(this.value2, other.value2);
// if those values matched, then compare value1 integers
// also sort descending
if (cmp == 0) {
cmp = -1 * Integer.compare(this.value1, other.value1);
}
// if those values matched, then compare dates ascending
if (cmp == 0) {
cmp = this.date.compareTo(other.date);
}
}
return cmp;
}
@Override
public String toString() {
return String.format("%s;%d;%d", date, value1, value2);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.