我有一个有性别的名字列表,以及有多少人有这个名字。
例如:
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;
}
}
}
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());
}
顺便说一句,你似乎可以";"简化";您的代码使用称为方法引用的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);
只需在第二次比较后打印结果。Collections.sort使用"稳定排序"算法,这意味着对于第二次排序中的相等项,顺序与第一次排序后的顺序保持不变,这正是您想要的,不是吗?
请参阅http://en.wikipedia.org/wiki/Sorting_algorithm#Stability
当然,更好的解决方案是组合比较器,因此您只需要对项目进行一次遍历。