如何使用Comparator对ArrayList <string>进行排序?

时间:2018-06-16 10:55:29

标签: java sorting arraylist comparator

嘿伙计们我试图为我的游戏制作记分牌,因此我需要对其进行排序。我的输入是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]);
        }
    }
});

3 个答案:

答案 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);
    }
}