如何使用两种排序对ArrayList进行排序

时间:2014-10-01 20:10:11

标签: java sorting arraylist

我有一个包含性别的名称列表,以及有多少人拥有该名称的计数。

例如:

John M 600

Mike M 200

Sarah F 700

Tom M 400

Emily F 600

Chris M 600

我正在尝试按计数降序对名称进行排序,如果它们具有相同的计数,我希望它们按ABC顺序排序。我单独制作的函数按ABC顺序打印计数,然后打印另一个按降序排列的计数。

示例:正在发生的事情

Chris M 600

Emily F 600

Mike M 200

John M 600

Sarah F 700

Tom M 400

Sarah F 700

John M 600

Emily F 600

Chris M 600

Tom M 400

Mike M 200

我想要的是什么

Sarah F 700

Chris M 600

Emily F 600

John M 600

Tom M 400

Mike M 200

ArrayList<OneName> oneName = new ArrayList<OneName>();
while(sc.hasNextLine())
    {

    // read a line from the input file via sc into line
        line = sc.nextLine();



        StringTokenizer stk = new StringTokenizer(line, ",");
        String name = stk.nextToken();
        char sex = stk.nextToken().charAt(0);
        int count = Integer.parseInt(stk.nextToken());


        OneName list = new OneName(name, sex, count);

        oneName.add(list);      



    }    Collections.sort(oneName, new OneNameCompare());

    for(OneName a: oneName)
    {
        System.out.println(a.toString());

    }
     Collections.sort(oneName, new OneNameCountCompare());
     for(OneName b: oneName)
    {

        System.out.println(b.toString());


     }

OneNameCompare.java

import java.util.Comparator;
import java.util.Collections;
public class OneNameCompare implements Comparator<OneName>
{

    public int compare(OneName a1, OneName a2)
    {
         return a1.getName().compareTo(a2.getName());
    }


 }

OneNameCountCompare.java

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

public class OneNameCountCompare implements Comparator<OneName>
{
    {
     if(b1.getCount() < b2.getCount())
     {
        return 1;
     }
 else
 {
    return -1; 
 }
}
}

2 个答案:

答案 0 :(得分:2)

Java 8解决方案

您可以通过引入Java 8中Comparator的thenComparing(Comparator<? super T> other)方法将两个比较器组合在一起。

所以而不是

Collections.sort(oneName, new OneNameCompare());
for (OneName a : oneName) {
    System.out.println(a.toString());

}

Collections.sort(oneName, new OneNameCountCompare());
for (OneName b : oneName) {
    System.out.println(b.toString());
}

使用

Collections.sort(oneName, new OneNameCountCompare()
                              .thenComparing(new OneNameCompare()));
for (OneName b : oneName) {
    System.out.println(b.toString());
}

顺便说一下,您似乎可以使用名为method references的新Java 8功能“简化”您的代码,以简单地创建所需的比较器。

import static java.util.Comparator.comparing;

//...

Comparator<OneName> reversedCountComparator = comparing(OneName::getCount).reversed();
Comparator<OneName> nameComparator = comparing(OneName::getName);

oneName.sort(reversedCountComparator.thenComparing(nameComparator));

oneName.forEach(System.out::println);

Java 7解决方案。

由于Collections.sort(collection, comparator)只接受一个比较器,因此您需要创建将实现Comparator的类,但将在内部使用您的其他比较器。这类的代码看起来像

class ComparatorsMixer<T> implements Comparator<T> {
    List<Comparator<T>> comparatorsList;

    public ComparatorsMixer(List<Comparator<T>> list) {
        this.comparatorsList = list;
    }

    public ComparatorsMixer() {
        comparatorsList = new ArrayList<>();
    }

    public void addComparator(Comparator<T> comparator){
        comparatorsList.add(comparator);
    }

    public int compare(T o1, T o2) {
        for (Comparator<T> c : comparatorsList) {
            int result = c.compare(o1, o2);
            if (result != 0)
                return result;
            //if result == 0 then move on to next comparator
        }
        return 0;
    }
}

你可以像

一样使用它
ComparatorsMixer<OneName> mix = new ComparatorsMixer<>();
mix.addComparator(new OneNameCountCompare());
mix.addComparator(new OneNameCompare());

Collections.sort(oneName, mix);

答案 1 :(得分:1)

只需在第二次比较后打印结果。 Collections.sort使用了一种稳定的排序&#39;算法,这意味着对于第二种排序中的相同项目,顺序保持与第一次排序后相同,这正是您想要的,不是吗?

请参阅http://en.wikipedia.org/wiki/Sorting_algorithm#Stability

当然,更好的解决方案是组合比较器,因此您只需要对项目进行一次传递。