简体   繁体   English

使用compareTo排序对象(多种类型)

[英]Sorting objects using compareTo (multiple types)

So first, I have an object called news article that has three properties that I need to sort by: 首先,我有一个名为新闻文章的对象,它有三个我需要排序的属性:

Year (int), Month (int), type (String - online, paper) 年(int),月(int),类型(字符串 - 在线,纸张)

So for example, it would be like this: 例如,它会是这样的:

  • Online 2013 4 在线2013 4
  • Online 2013 1 在线2013 1
  • Online 2009 11 在线2009 11
  • Online 2008 4 在线2008 4
  • Paper 2012 12 论文2012 12
  • Paper 2011 9 论文2011 9

What is going on is that the month and year appear to be sorting correctly, but I'm having problems sorting by type. 发生的事情是月份和年份似乎正确排序,但我遇到按类型排序的问题。 What's the proper way to sort by String in a compareTo? 在compareTo中按字符串排序的正确方法是什么?

Results at the moment: 结果目前:

  • Paper 2012 12 论文2012 12
  • Paper 2011 9 论文2011 9
  • Online 2013 4 在线2013 4
  • Online 2013 1 在线2013 1
  • Online 2009 11 在线2009 11
  • Online 2008 4 在线2008 4

Here's my method (I apologize for it being somewhat quirky, I've been trying different ways to sort by the type and was experimenting): 这是我的方法(我为它有点古怪而道歉,我一直在尝试不同的方式按类型排序并进行实验):

@Override
public int compareTo(Article rs) {

    Integer x = 0;


        Integer year1 = 0;
        Integer year2 = 0;
        Integer month1 = 99999;
        Integer month2 = 99999;
        Integer type1 = 99999;
        Integer type2 = 99999;

        if(rs.year != null && year != null) {

            if(!rs.year.equals(""))
                year1 = Integer.parseInt(rs.year);
            if(!year.equals(""))
                year2 = Integer.parseInt(year);
        }

        if(rs.month != null && month != null) {
            if(!rs.month.equals(""))
                month1 = Integer.parseInt(rs.month);
            if(!month.equals(""))
                month2 = Integer.parseInt(month);
        }

        if(rs.type == null)
            type1 = 99999;
        else
            type1 = 0;

        if(type == null)
            type2 = 99999;
        else
            type2 = 0;

        x = type2.compareTo(type1);
        if(x != 0) {
            return x;
        }

        x = year1.compareTo(year2);
        if(x != 0) {
            return x;
        }

        x = month1.compareTo(month2);
        if(x != 0) {
            return x;
        }


    return x;
}

I would refactor (eg throw away) your complete code and replace it by using CompareToBuilder . 我会重构(例如扔掉)你的完整代码并使用CompareToBuilder替换它。

This will create the following code: 这将创建以下代码:

enum ArticleType {
    ONLINE, PAPER
}

class Article implements Comparable<Article> {

    int year;
    int month;
    ArticleType type;

    Article(int year, int month, ArticleType type) {
        this.year = year;
        this.type = type;
        this.month = month;
    }

    @Override
    public int compareTo(Article o) {
        return new CompareToBuilder()
                .append(this.type, o.type)
                .append(this.year, o.year)
                .append(this.month, o.month)
                .toComparison();

    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("month", month)
                .add("year", year)
                .add("type", type)
                .toString();
    }
}

@Test
public void testSortArticles() throws Exception {
    List<Article> articleList = new ArrayList<>();
    articleList.add(new Article(2012, 1, ArticleType.ONLINE));
    articleList.add(new Article(2011, 1, ArticleType.ONLINE));
    articleList.add(new Article(2011, 6, ArticleType.ONLINE));
    articleList.add(new Article(2010, 1, ArticleType.ONLINE));
    articleList.add(new Article(2010, 1, ArticleType.PAPER));
    articleList.add(new Article(2010, 2, ArticleType.PAPER));
    articleList.add(new Article(2010, 3, ArticleType.PAPER));
    articleList.add(new Article(2012, 1, ArticleType.PAPER));
    articleList.add(new Article(2012, 9, ArticleType.PAPER));

    Collections.sort(articleList);

    System.out.println(articleList);
}

Printing this will lead to the following: 打印此将导致以下内容:

[Article{month=1, year=2010, type=ONLINE}, Article{month=1, year=2010, type=PAPER},
 Article{month=2, year=2010, type=PAPER}, Article{month=3, year=2010, type=PAPER},
 Article{month=1, year=2011, type=ONLINE}, Article{month=6, year=2011, type=ONLINE},
 Article{month=1, year=2012, type=ONLINE}, Article{month=1, year=2012, type=PAPER},
 Article{month=9, year=2012, type=PAPER}]

Will provides a nicely sorted list. Will提供了一个排序很好的列表。 The offline/online is sorted too using an Enum (ArticleType). 离线/在线也使用Enum(ArticleType)进行排序。 In my opinion, this looks a bit better than your current implementation. 在我看来,这看起来比你当前的实现好一点。

If the type is not null, you replace it by 0, whatever its value is. 如果类型不为null,则将其替换为0,无论其值是什么。 So comparing "paper" with "online" leads to comparing 0 with 0, which is obviously wrong. 因此,将“纸张”与“在线”进行比较会导致将0与0进行比较,这显然是错误的。

My first advice would be to use proper types instead of String for everything. 我的第一个建议是使用适当的类型而不是String。 month and year should be int s, and type should be an enum. 月份和年份应为int ,类型应为枚举。 You should also strive to make them non-nullable. 你还应努力使它们不可为空。

Once done, the comparison method would reduce to 完成后,比较方法将减少到

public int compareTo(Article other) {
    int result = this.type.compareTo(other.type);
    if (result == 0) {
        result = Integer.compare(this.year, other.year);
    }
    if (result == 0) {
        result = Integer.compare(this.month, other.month);
    }
    return result;
}

Note that using an enum allows you to dictate specify the way types compare, simply by listing the values in the order you want. 请注意,使用枚举允许您指定类型比较的方式,只需按所需顺序列出值即可。

Or even better, with Guava: 甚至更好,与番石榴:

public int compareTo(Article other) {
    return ComparisonChain.start()
                          .compare(this.type, other.type)
                          .compare(this.year, other.year)
                          .compare(this.month, other.month)
                          .result();
}

If the values are nullable, the above code would have to be changed to 如果值可以为空,则必须将上述代码更改为

public int compareTo(Article other) {
    return ComparisonChain.start()
                .compare(this.type, other.type, Ordering.natural().nullsLast())
                .compare(this.year, other.year, Ordering.natural().nullsLast())
                .compare(this.month, other.month, Ordering.natural().nullsLast())
                .result();
}

To answer your question, you can simply use compareTo() to compare two String objects. 要回答您的问题,您只需使用compareTo()来比较两个String对象。 You just have to make sure that you compare them in the order that you want. 您只需确保按照所需的顺序对它们进行比较。 Doing

x = type2.compareTo(type1);

compares the String s in descending order . 比较String s的降序 If you want to sort in ascending order, you need to do 如果要按升序排序,则需要执行此操作

x = type1.compareTo(type2);

In adition, I am curious about all the == null or != null checks. 在adition中,我对所有== null!= null检查感到好奇。 Since this is your own class, you should control whether or not the member fields can be null . 由于这是您自己的类,因此您应该控制成员字段是否为null If I were writing a similar class, I would require that all fields are initialized by the constructor so that I don't need to check for null values. 如果我正在编写类似的类,我会要求所有字段都由构造函数初始化,这样我就不需要检查null值。 This can greatly simplify all the other methods in the class, including this compareTo() method. 这可以大大简化类中的所有其他方法,包括compareTo()方法。

Also, you should prefer built-in types over wrapper classes. 此外,您应该更喜欢内置类型而不是包装类。 In other words, use int s for the year and month fields rather than Integer s. 换句话说,使用int s表示年份和月份字段而不是Integer This can also help simplify your code in a couple of ways. 这也可以通过几种方式帮助简化代码。 First, you won't have to worry about null values. 首先,您不必担心null值。 Second, you can compare to int s with a simple subtraction: 其次,您可以使用简单的减法与int进行比较:

int compareYears = this.year - rs.year;
if (compareYears != 0) {
    return compareYears;
}

With these suggestions, you can not only fix the current problem, but you can also reduce the number of lines of code by at least half. 有了这些建议,您不仅可以解决当前问题,还可以将代码行数减少至少一半。

(Note that in general, you must be careful about comparing int s using subtraction due to overflow. In this case, since we are comparing years, neither value should be negative, so there shouldn't be a problem. Of course, the rest of your class should enforce that the year field is in fact a valid year.) (注意,一般情况下,由于溢出,你必须小心使用减法来比较int 。在这种情况下,由于我们比较年份,因此两个值都不应该是负数,所以不应该有问题。当然,其余的您的班级应该强制year字段实际上是有效年份。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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