1

因此,首先,我有一个名为 news article 的对象,它具有三个需要排序的属性:

Year (int), Month (int), type (String - online, paper)

例如,它会是这样的:

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

发生的事情是月份和年份似乎正确排序,但我在按类型排序时遇到问题。在 compareTo 中按字符串排序的正确方法是什么?

目前结果:

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

这是我的方法(我很抱歉它有点古怪,我一直在尝试不同的方法来按类型排序并且正在试验):

@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;
}
4

3 回答 3

3

我会重构(例如丢弃)您的完整代码并使用CompareToBuilder替换它。

这将创建以下代码:

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

打印这将导致以下结果:

[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 提供了一个排序良好的列表。离线/在线也使用枚举(ArticleType)进行排序。在我看来,这看起来比您当前的实现要好一些。

于 2013-07-08T21:20:59.797 回答
1

如果类型不为 null,则将其替换为 0,无论其值是什么。所以将“paper”与“online”进行比较导致将0与0进行比较,这显然是错误的。

我的第一个建议是对所有内容使用正确的类型而不是 String。月份和年份应为ints,类型应为枚举。您还应该努力使它们不可为空。

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();
}
于 2013-07-08T21:25:55.060 回答
0

要回答您的问题,您可以简单地使用compareTo()来比较两个String对象。您只需要确保按照您想要的顺序比较它们。正在做

x = type2.compareTo(type1);

按降序比较Strings 。如果你想按升序排序,你需要做

x = type1.compareTo(type2);

此外,我对所有的== null!= null检查感到好奇。由于这是你自己的类,你应该控制成员字段是否可以是null. 如果我正在编写一个类似的类,我会要求所有字段都由构造函数初始化,这样我就不需要检查null值。这可以大大简化类中的所有其他方法,包括这个compareTo()方法。

此外,您应该更喜欢内置类型而不是包装类。换句话说,int对年和月字段使用 s 而不是Integers。这还可以通过多种方式帮助简化您的代码。首先,您不必担心null值。其次,您可以int通过简单的减法与 s 进行比较:

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

有了这些建议,你不仅可以修复当前的问题,还可以将代码行数减少至少一半。

(请注意,一般情况下,由于溢出,您必须小心int使用减法比较 s。在这种情况下,由于我们正在比较年份,所以两个值都不应该是负数,所以应该没有问题。当然,其余的您的班级应该强制该year字段实际上是有效的年份。)

于 2013-07-08T21:21:03.393 回答