Java 物件陣列多屬性條件排序問題(詳解)

Plutoaaa發表於2018-02-13
最近遇到了一道多條件排序題,類似於“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後按Enter鍵會被讀成nextline,如果這裡不用temp過濾掉這個Enter鍵,對下面會有一定影響
		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());
		}
	}
}

現在假設我們的輸入資料是這樣的:


那麼以上程式的最終執行結果為:





相關文章