Java 的 Comparator 对多个排序条件的处理?

红薯 发布于 2011/06/02 09:22
阅读 13K+
收藏 7

假设一个雇员对象,包含级别、工资和入职年份(为了简单,这些属性写成 public),代码如下:

public Class Employee {

    public int level;  //级别
    public int salary; //工资
    public int years;  //入职年数

}

现在我需要做一个这样的雇员列表,首先级别最高的排在前面,如果级别相等,那么按工资排序,工资高的排在前面,如果工资相当则按入职年数排序,入职时间最长的排在前面。

因为雇员列表是在内存中的一个 List<Employee> 对象,现在要对这个 List 中的雇员按上面的要求进行排序 Collections.sort(employeeList, comparator),那么这个 Comparator 应该怎么写呢?

下面这种肯定是不对的

Comparator<Employee> cp_by_default = new Comparator<Employee>(){
	@Override
	public int compare(Employee a1, Employee a2) {
		int a = a2.level - a1.level;
		if(a > 0)
			return a;
		a = a2.salary - a1.salary;
		if(a > 0)
			return a;
		return a2.years - a1.years;
	}		
};
加载中
1
红薯
红薯

写了个测试类,测试OK

package net.oschina.tester;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 多个排序条件测试
 * @author Winter Lau (http://my.oschina.net/javayou)
 * @date 2011-6-2 上午9:56:27
 */
public class Employee {

	public static void main(String[] args) {
		List<Employee> objs = new ArrayList<Employee>(){{
			add(new Employee(5,3,5000,2));
			add(new Employee(1,9,10000,10));
			add(new Employee(4,5,8000,6));
			add(new Employee(2,9,12000,7));
			add(new Employee(6,1,2000,1));
			add(new Employee(3,5,8000,12));
		}};
		Collections.sort(objs, comparator);
		System.out.println("No\tLevel\tSalary\tYears\n=============================");
		for(Employee a : objs)
			System.out.printf("%d\t%d\t%d\t%d\n",a.id,a.level,a.salary,a.year);
	}

	public Employee(int id, int level, int salary, int year){
		this.id = id;
		this.level = level;
		this.salary = salary;
		this.year = year;
	}
	
	public int id;
	public int level;
	public int salary;
	public int year;

	private final static Comparator<Employee> comparator = new Comparator<Employee>(){
		@Override
		public int compare(Employee a1, Employee a2) {
			int cr = 0;
			int a = a2.level - a1.level;
			if(a != 0)
				cr = (a>0)?3:-1;
			else{
				a = a2.salary - a1.salary;
				if(a != 0)
					cr = (a>0)?2:-2;
				else{
					a = (int)(a2.year - a1.year);
					if(a != 0)
						cr = (a>0)?1:-3;
				}
			}
			//System.out.printf("compare(%d,%d)=%d\n", a1.getId(), a2.getId(), cr);
			return cr;
		}		
	};
	
}
卡布达巨人
卡布达巨人
a!=0 直接return cr就成了
1
fxsjy
fxsjy

int x = a1.level - a2.level
int y = a1.salary - a2.salary
int z = a1.years - a2.years
if(x==0){
     if(y==0){
            return z;
     }
     return y;
}
return x;

jinceon
jinceon
别抽我,我真的不懂权重。
红薯
红薯
这种方法没有考虑到权重的问题哦
1
黄平俊
黄平俊
package com.lewole;

import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;

/**
 * Sort <code>List</code> by multiple conditions.<br> 
 * It's like SQL 'Order by' clause. Input multiple <code>Comparator</code> 
 * @author jimmy ideajava@gmail.com
 * @param <T>
 */
public class GroupComparator<T> implements Comparator<T>{
	private List<Comparator<T>> comparators = new ArrayList<Comparator<T>>();
	public GroupComparator(Comparator<T> first, Comparator<T> second){
		comparators.add( first );
		comparators.add( second );
	}
 	
	public void addComparator(Comparator<T> comparator){
		comparators.add( comparator );
	}

	public int compare(T t1, T t2){
		for (Comparator<T> comparator : comparators)
		{
			int returnValue = comparator.compare(t1, t2);

			if (returnValue != 0)
				return returnValue;
		}

		return 0;
	}
}

使用方法:

Comparator<TopicBean> sort1 = new Comparator<TopicBean>(){
   			public int compare(TopicBean t1, TopicBean t2) {
   				return t1.getDown() - t2.getDown();
 			}
 		};
 		
 		Comparator<TopicBean> sort2 = new Comparator<TopicBean>(){
   			public int compare(TopicBean t1, TopicBean t2) {
   				return t1.getCatId() - t2.getCatId();
 			}
 		};
 		
 		Comparator<TopicBean> sort3 = new Comparator<TopicBean>(){
   			public int compare(TopicBean t1, TopicBean t2) {
   				return t1.getUp()- t2.getUp();
 			}
 		};
  		GroupComparator<TopicBean> gc = new GroupComparator<TopicBean>(sort1,sort2);
  		gc.addComparator(sort3);
                ..............
 	
 		Collections.sort(topics,gc);

0
jinceon
jinceon

明白了,确实有很大错误。连续排两次,得到的结果是完全不同的

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Test
{
	public void sortT(List<Employee> list)
	{
		Collections.sort(list, new Comparator<Employee>()
		{
			@Override
			public int compare(Employee a1, Employee a2)
			{
				int a = a2.level - a1.level;
				if (a > 0)
					return a;
				a = a2.salary - a1.salary;
				if (a > 0)
					return a;
				return a2.years - a1.years;
			}
		});
	}

	public void sortA(List<Employee> list)
	{
		Collections.sort(list, new Comparator<Employee>()
		{
			@Override
			public int compare(Employee a1, Employee a2)
			{
				int x = a1.level - a2.level;
				int y = a1.salary - a2.salary;
				int z = a1.years - a2.years;
				if (x == 0)
				{
					if (y == 0)
					{
						return -z;
					}
					return -y;
				}
				return -x;
			}
		});
	}

	public static void main(String[] args)
	{
		List<Employee> list = new ArrayList<Employee>();
		list.add(new Employee(1, 1, 2, 3));
		list.add(new Employee(2, 1, 1, 3));
		list.add(new Employee(3, 1, 2, 2));
		list.add(new Employee(4, 2, 2, 3));
		list.add(new Employee(5, 2, 1, 3));
		list.add(new Employee(6, 2, 2, 1));
		Test tt = new Test();
		tt.sortT(list);
		for (Employee e : list)
		{
			System.out.println(e);
		}
		System.out.println("===================");
		tt.sortT(list);
		for (Employee e : list)
		{
			System.out.println(e);
		}
	}
}

class Employee
{
	int id;
	int level;
	int salary;
	int years;

	public Employee(int id, int level, int salary, int years)
	{
		this.id = id;
		this.level = level;
		this.salary = salary;
		this.years = years;
	}

	public String toString()
	{
		return id + "  " + level + "   " + salary + "   " + years;
	}
}
0
jinceon
jinceon
我想顶【有帮助】,结果没积分。
红薯
红薯
我刚顶了你的答案,一天过后积分就会到你手了,呵呵:)
0
fxsjy
fxsjy

权重是啥?我用我的方法排出来和红薯的没有差别啊。

附代码:

 

package fx.sunjoy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Employee {

	public static void main(String[] args) {
		List<Employee> objs = new ArrayList<Employee>(){{
			add(new Employee(5,3,5000,2));
			add(new Employee(1,9,10000,10));
			add(new Employee(4,5,8000,6));
			add(new Employee(2,9,12000,7));
			add(new Employee(6,1,2000,1));
			add(new Employee(3,5,8000,12));
		}};
		Collections.sort(objs, comparator);
		System.out.println("No\tLevel\tSalary\tYears\n=============================");
		for(Employee a : objs)
			System.out.printf("%d\t%d\t%d\t%d\n",a.id,a.level,a.salary,a.year);
		System.out.println("");
		Collections.sort(objs, sjycmp);
		System.out.println("No\tLevel\tSalary\tYears\n=============================");
		for(Employee a : objs)
			System.out.printf("%d\t%d\t%d\t%d\n",a.id,a.level,a.salary,a.year);
		
	}

	public Employee(int id, int level, int salary, int year){
		this.id = id;
		this.level = level;
		this.salary = salary;
		this.year = year;
	}
	
	public int id;
	public int level;
	public int salary;
	public int year;

	private final static Comparator<Employee> sjycmp = new Comparator<Employee>() {

		@Override
		public int compare(Employee a1, Employee a2) {
			int x = a1.level - a2.level;
			int y = a1.salary - a2.salary;
			int z = a1.year - a2.year;
			if(x==0){
			     if(y==0){
			            return -z;
			     }
			     return -y;
			}
			return -x;
		}
		
	};
	
	private final static Comparator<Employee> comparator = new Comparator<Employee>(){
		@Override
		public int compare(Employee a1, Employee a2) {
			int cr = 0;
			int a = a2.level - a1.level;
			if(a != 0)
				cr = (a>0)?3:-1;
			else{
				a = a2.salary - a1.salary;
				if(a != 0)
					cr = (a>0)?2:-2;
				else{
					a = (int)(a2.year - a1.year);
					if(a != 0)
						cr = (a>0)?1:-3;
				}
			}
			//System.out.printf("compare(%d,%d)=%d\n", a1.getId(), a2.getId(), cr);
			return cr;
		}		
	};
	
}
jinceon
jinceon
红薯的if(a > 0)改成if(a != 0)就和你的一样了。我也不懂权重的区别
0
RainJ
RainJ

关键是Collections.sort才不关心权重呢,因为它只会通过正负来比较, 详见:

private static void mergeSort(Object[] src,
				  Object[] dest,
				  int low, int high, int off,
				  Comparator c) {
	int length = high - low;

	// Insertion sort on smallest arrays
	if (length < INSERTIONSORT_THRESHOLD) {
	    for (int i=low; i<high; i++)
		for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
		    swap(dest, j, j-1);
	    return;
	}

        // Recursively sort halves of dest into src
        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off, c);
        mergeSort(dest, src, mid, high, -off, c);

        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (c.compare(src[mid-1], src[mid]) <= 0) {
           System.arraycopy(src, low, dest, destLow, length);
           return;
        }

        // Merge sorted halves (now in src) into dest
        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }

fxsjy
fxsjy
呃,原来是是这个意思。。。
0
601097836
601097836

此类compartor多重排序问题,这个页面google搜索排名第一,感觉对不起google啊,请把我顶上去好吗?

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * User:ThinerZQ
 * Email:thinerzq@gmail.com
 * Date:2016/9/23 14:37
 * Project:Test
 * Package:PACKAGE_NAME
 */
public class TestCompartor {
    public static void main(String[] args) {

        ArrayList<Person> persons = new ArrayList<Person>();
        persons.add(new Person(10,1000,4));
        persons.add(new Person(1,1020,5));
        persons.add(new Person(1,1020,4));
        persons.add(new Person(13,1100,2));
        persons.add(new Person(1,1020,5));
        for (int i = 0; i <persons.size(); i++) {
            System.out.println(persons.get(i));
        }
        System.out.println();
        Collections.sort(persons, new Comparator<Person>() {
            //级别,年份,薪资排序降序,
            public int compare(Person o1, Person o2) {
                if (o1.level == o2.level){
                    if (o1.salary == o2.salary){
                        return o2.years - o1.years;
                    }else{
                        return o2.salary - o1.salary;
                    }
                }else{
                    return o2.level - o1.level;
                }
            }
        });
        for (int i = 0; i <persons.size(); i++) {
            System.out.println(persons.get(i));
        }
    }
    static class Person{
        public int level;  //级别
        public int salary; //工资
        public int years;  //入职年数

        @Override
        public String toString() {
            return "Person{" +
                    "level=" + level +
                    ", salary=" + salary +
                    ", years=" + years +
                    '}';
        }
        public Person(int level, int salary, int years) {
            this.level = level;
            this.salary = salary;
            this.years = years;
        }
    }
}



0
追寻_

引用来自“601097836”的评论

此类compartor多重排序问题,这个页面google搜索排名第一,感觉对不起google啊,请把我顶上去好吗?

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * User:ThinerZQ
 * Email:thinerzq@gmail.com
 * Date:2016/9/23 14:37
 * Project:Test
 * Package:PACKAGE_NAME
 */
public class TestCompartor {
    public static void main(String[] args) {

        ArrayList<Person> persons = new ArrayList<Person>();
        persons.add(new Person(10,1000,4));
        persons.add(new Person(1,1020,5));
        persons.add(new Person(1,1020,4));
        persons.add(new Person(13,1100,2));
        persons.add(new Person(1,1020,5));
        for (int i = 0; i <persons.size(); i++) {
            System.out.println(persons.get(i));
        }
        System.out.println();
        Collections.sort(persons, new Comparator<Person>() {
            //级别,年份,薪资排序降序,
            public int compare(Person o1, Person o2) {
                if (o1.level == o2.level){
                    if (o1.salary == o2.salary){
                        return o2.years - o1.years;
                    }else{
                        return o2.salary - o1.salary;
                    }
                }else{
                    return o2.level - o1.level;
                }
            }
        });
        for (int i = 0; i <persons.size(); i++) {
            System.out.println(persons.get(i));
        }
    }
    static class Person{
        public int level;  //级别
        public int salary; //工资
        public int years;  //入职年数

        @Override
        public String toString() {
            return "Person{" +
                    "level=" + level +
                    ", salary=" + salary +
                    ", years=" + years +
                    '}';
        }
        public Person(int level, int salary, int years) {
            this.level = level;
            this.salary = salary;
            this.years = years;
        }
    }
}



攒一个支持

返回顶部
顶部