最近遇到了一道多条件排序题,类似于“something有A,B,C三个属性,先比较A,A条件相同时再比较B,B条件相同时再比较C,排序输出”的形式。这类题目用C/C++解决起来会很顺手,可以用结构体,结合sort和compare,就能完成整个思路。但是我们如何用Java来解决这个问题呢。Java是面向对象的语言,没有结构体的概念,我们应该定义类。
比方说,用一个球队排名问题来举例子。
现在对象是球队信息Info,有四个属性:球队名name、球队的积分x、净胜球y、进球数z。那么我们这样定义类:
class Info {
private String name;
private int x;
private int y;
private int z;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getx() {
return x;
}
public void setx(int x) {
this.x = x;
}
public int gety() {
return y;
}
public void sety(int y) {
this.y = y;
}
public int getz() {
return z;
}
public void setz(int z) {
this.z = z;
}
}那么下面的问题是,主函数怎么写。
我们考虑最复杂的一种情况,就是首先输入数据组数N,然后依次输入每组数据,每组属性里均包含对象的四个属性,这里就要用到对象数组来实现,引入对象数组a [ ] , a[ i ] 中依次存入第 i 组数据对象的四个属性。接着,把对象数组add到集合b中,这样做方便我们进行多属性的条件排序。
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
String temp = sc.nextLine(); // 输入N后按回车键会被读成nextline,如果这里不用temp过滤掉这个回车键,对下面会有一定影响
Info[] a = new Info[N+1];
List<Info> b = new ArrayList();
for (int i = 0; i < N; i++) {
String str = sc.nextLine();
String[] s = str.split(" ");
a[i] = new Info(); //这一行很重要
a[i].setName(s[0]);
a[i].setx(Integer.parseInt(s[1]));
a[i].sety(Integer.parseInt(s[2]));
a[i].setz(Integer.parseInt(s[3]));
b.add(a[i]);
}剩下的问题是,怎样实现多属性的排序,假设我们这样规定:先比较积分x,如果积分x相同则比较净胜球y,如果积分x、净胜球y都相同则比较进球数z。刚刚我们已经将对象数组存在了集合里,其实下面很简单,运用Collections.sort和Comparator就可以解决:
Collections.sort(b, new Comparator<Info>() {
public int compare(Info team1, Info team2) {
int x = team1.getx() - team2.getx();
int y = team1.gety() - team2.gety();
int z = team1.getz() - team2.getz();
if (x == 0) {
if (y == 0) {
return z;
}
return y;
}
return x;
}
});现在我们再去考虑一种复杂一点的,假设我们把规定改为:先比较积分x,积分x高者名次在前,如果积分x相同则比较净胜球y,净胜球y多者名次在前,如果积分x、净胜球y都相同则比较进球数z,进球数多者名次在前。也就是说,我们需要讲这些多属性多条件进行降序排序,应该如何修改上面的代码呢。思考一下再进行参考:
Collections.sort(b, new Comparator<Info>() {
public int compare(Info team1, Info team2) {
int x = team1.getx() - team2.getx();
int y = team1.gety() - team2.gety();
int z = team1.getz() - team2.getz();
if (x != 0) {
return x > 0 ? -1:1;
}
if (y != 0) {
return y > 0 ? -1:1;
}
return z > 0 ? -1:1;
}
});再延伸一点,很多题目会出现要求当前面的属性x,y,z都相同时,按照球队名称字典序排列。其实这也不难,在上面的基础上加几行就可以:
Collections.sort(b, new Comparator<Info>() {
public int compare(Info team1, Info team2) {
int x = team1.getx() - team2.getx();
int y = team1.gety() - team2.gety();
int z = team1.getz() - team2.getz();
if (x != 0) {
return x > 0 ? -1:1;
}
if (y != 0) {
return y > 0 ? -1:1;
}
if(z!=0) {
return z > 0 ? -1:1;
}
return team1.name.compareTo(team2.name);
}
});最后,我们假设这里只要求输出排序后的球队名称:
for (Info result : b) {
System.out.println(result.getName());
}整个思路就都完成了。
另外还需要提一点,我们的main函数是static静态的,但是我们定义的类Info默认属于内部动态类,这会导致调试的时候出错,所以在完善程序的时候,我们可以把类也定义成static。最后整理一下全部思路是这样的:(按照提到的第二种降序输出)
import java.util.*;
public class Main {
static class Info {
private String name;
private int x;
private int y;
private int z;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getx() {
return x;
}
public void setx(int x) {
this.x = x;
}
public int gety() {
return y;
}
public void sety(int y) {
this.y = y;
}
public int getz() {
return z;
}
public void setz(int z) {
this.z = z;
}
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
String temp = sc.nextLine();
Info[] a = new Info[N+1];
List<Info> b = new ArrayList();
for (int i = 0; i < N; i++) {
String str = sc.nextLine();
String[] s = str.split(" ");
a[i] = new Info();
a[i].setName(s[0]);
a[i].setx(Integer.parseInt(s[1]));
a[i].sety(Integer.parseInt(s[2]));
a[i].setz(Integer.parseInt(s[3]));
b.add(a[i]);
}
Collections.sort(b, new Comparator<Info>() {
public int compare(Info team1, Info team2) {
int x = team1.getx() - team2.getx();
int y = team1.gety() - team2.gety();
int z = team1.getz() - team2.getz();
if (x != 0) {
return x > 0 ? -1:1;
}
if (y != 0) {
return y > 0 ? -1:1;
}
if(z!=0) {
return z > 0 ? -1:1;
}
return team1.name.compareTo(team2.name);
}
});
for (Info result : b) {
System.out.println(result.getName());
}
}
}现在假设我们的输入数据是这样的:
那么以上程序的最终运行结果为:
本文详细讲解了如何使用Java对包含多个属性的对象数组进行排序,首先按照积分x升序,若积分相同则根据净胜球y升序,如积分和净胜球都相同则依据进球数z升序。当所有属性都相同时,按球队名称字典序排列。文章还解决了静态main函数与非静态内部类导致的调试问题,并提供了具体的代码实现和排序后的结果展示。
358





