[英]Sorting objects using compareTo (multiple types)
首先,我有一个名为新闻文章的对象,它有三个我需要排序的属性:
年(int),月(int),类型(字符串 - 在线,纸张)
例如,它会是这样的:
发生的事情是月份和年份似乎正确排序,但我遇到按类型排序的问题。 在compareTo中按字符串排序的正确方法是什么?
结果目前:
这是我的方法(我为它有点古怪而道歉,我一直在尝试不同的方式按类型排序并进行实验):
@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;
}
我会重构(例如扔掉)你的完整代码并使用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提供了一个排序很好的列表。 离线/在线也使用Enum(ArticleType)进行排序。 在我看来,这看起来比你当前的实现好一点。
如果类型不为null,则将其替换为0,无论其值是什么。 因此,将“纸张”与“在线”进行比较会导致将0与0进行比较,这显然是错误的。
我的第一个建议是使用适当的类型而不是String。 月份和年份应为int
,类型应为枚举。 你还应努力使它们不可为空。
完成后,比较方法将减少到
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;
}
请注意,使用枚举允许您指定类型比较的方式,只需按所需顺序列出值即可。
甚至更好,与番石榴:
public int compareTo(Article other) {
return ComparisonChain.start()
.compare(this.type, other.type)
.compare(this.year, other.year)
.compare(this.month, other.month)
.result();
}
如果值可以为空,则必须将上述代码更改为
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();
}
要回答您的问题,您只需使用compareTo()
来比较两个String
对象。 您只需确保按照所需的顺序对它们进行比较。 干
x = type2.compareTo(type1);
比较String
s的降序 。 如果要按升序排序,则需要执行此操作
x = type1.compareTo(type2);
在adition中,我对所有== null
或!= null
检查感到好奇。 由于这是您自己的类,因此您应该控制成员字段是否为null
。 如果我正在编写类似的类,我会要求所有字段都由构造函数初始化,这样我就不需要检查null
值。 这可以大大简化类中的所有其他方法,包括compareTo()
方法。
此外,您应该更喜欢内置类型而不是包装类。 换句话说,使用int
s表示年份和月份字段而不是Integer
。 这也可以通过几种方式帮助简化代码。 首先,您不必担心null
值。 其次,您可以使用简单的减法与int
进行比较:
int compareYears = this.year - rs.year;
if (compareYears != 0) {
return compareYears;
}
有了这些建议,您不仅可以解决当前问题,还可以将代码行数减少至少一半。
(注意,一般情况下,由于溢出,你必须小心使用减法来比较int
。在这种情况下,由于我们比较年份,因此两个值都不应该是负数,所以不应该有问题。当然,其余的您的班级应该强制year
字段实际上是有效年份。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.