Java 对象数组多属性条件排序问题(详解)

本文详细讲解了如何使用Java对包含多个属性的对象数组进行排序,首先按照积分x升序,若积分相同则根据净胜球y升序,如积分和净胜球都相同则依据进球数z升序。当所有属性都相同时,按球队名称字典序排列。文章还解决了静态main函数与非静态内部类导致的调试问题,并提供了具体的代码实现和排序后的结果展示。
最近遇到了一道多条件排序题,类似于“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;
		}
	}

每一个属性相应分别有get和set两个方法,简要解释一下,比方说name属性的setName( ) 方法,作用是设置名称,我们在主函数里对对象的name属性进行赋值时就需要调用它,通过具体的参数值告诉程序你把他设置成什么名称,这是不需要返回值的,也就是定义类型是void的原因;那么getName( )方法,作用就是获取名称了,它不需要参数,程序把name通过返回值传回来,所以它的返回值类型是string。剩余几个举一反三即可,原理一样。

那么下面的问题是,主函数怎么写。
我们考虑最复杂的一种情况,就是首先输入数据组数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.sortComparator就可以解决:


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

现在假设我们的输入数据是这样的:


那么以上程序的最终运行结果为:





评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值