嘿伙计们我试图为我的游戏制作记分牌,因此我需要对其进行排序。我的输入是DATE; LEVEL; SCORE,我希望按最高分对它进行排序,如果它等于最高级别,并且它等于日期。
我的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");
应该排序
[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];
但我正在
[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]
我的代码:
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]);
}
}
});
答案 0 :(得分:4)
您正在使用基于字符串的词法比较,将"5"
视为大于"10"
(因为字符'5'
位于Unicode表中的'1'
之后)
相反,您应该使用数字比较。将字符串转换为整数,并将它们与Integer.compare
或类似字符进行比较:
而不是:
return tmp2[2].compareTo(tmp[2]);
你可以这样做:
return Integer.compare(
Integer.parseInt(tmp2[2]),
Integer.parseInt(tmp[2])
);
答案 1 :(得分:4)
如果您使用的是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));
使用此对象:
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
}
或没有对象:
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])));
注意:您可以按照您想要的顺序放置它们,这样您就可以获得预期的结果
答案 2 :(得分:1)
我喜欢@YCF_L的方法以及@jspcal如何正确到达目的。我通常会将其分解为可重用的组件。
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);
}
}