我有一个包含性别的名称列表,以及有多少人拥有该名称的计数。
例如:
John M 600
Mike M 200
Sarah F 700
Tom M 400
Emily F 600Chris M 600
我正在尝试按计数降序对名称进行排序,如果它们具有相同的计数,我希望它们按ABC顺序排序。我单独制作的函数按ABC顺序打印计数,然后打印另一个按降序排列的计数。
示例:正在发生的事情
Chris M 600
Emily F 600Mike M 200
John M 600
Sarah F 700
Tom M 400
Sarah F 700
John M 600
Emily F 600Chris M 600
Tom M 400
Mike M 200
我想要的是什么
Sarah F 700
Chris M 600
Emily F 600John 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;
}
}
}
答案 0 :(得分:2)
您可以通过引入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);
由于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
当然,更好的解决方案是组合比较器,因此您只需要对项目进行一次传递。