简体   繁体   English

如何对ArrayList进行排序 <String> 使用比较器?

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM