问题
I've got a simple java pojo which looks like this:
class MyClass
{
public String getGroup();
public String getTitle();
}
Now what I want to do is to primarily sort a list of MyClass pojo by the values returned by the getTitle() method. Easy going though using my own comparator. However, what I want is that instances with the same value returned by getGroup() being followed by each other. Now what I did was something like
.. compare(MyClass c1, MyClass c2)
{
if (c1.getGroup().compareTo(c2.getGroup()) == 0)
{
return c1.getTitle().compareTo(c2.getTitle());
}
return c1.getGroup().compareTo(c2.getGroup());
}
However, the issue of this code is that it is no longer primarily sorted by the title because I do first compare the content of the groups, not the title, so a group starting with "B" would come before a group starting with "C" eventhough its title may come first.. what's the proper way to primarily sort by title but make sure groups are "groupped" together as well?
Sample data:
MyClass 1 (group = "A", title="5")
MyClass 2 (group = "B", title="9")
MyClass 3 (group = "B", title="1")
Using my previous code would end up in
MyClass 1 (group = "A", title="5")
MyClass 3 (group = "B", title="1")
MyClass 2 (group = "B", title="9")
-> sort by group, then sort by title
But I want
MyClass 3 (group = "B", title="1")
MyClass 2 (group = "B", title="9")
MyClass 1 (group = "A", title="5")
-> sort by title but make sure each equal group follows each other that's why still MyClass 1 with title "5" comes after MyClass 2 with title "9"...
回答1:
Can't be done with a Comparator. You need to run through the sorted titles, then for each unvisited title sort the corresponding groups. Here's some sample code that sorts like the way you wanted.
public class MyClass {
private String group;
private String title;
public MyClass(String g, String t) {
group=g;
title=t;
}
static Comparator<MyClass> TITLE_COMPARATOR =
new Comparator<MyClass>() {
@Override
public int compare(MyClass c1, MyClass c2) {
return c1.title.compareTo(c2.title);
}
};
static Comparator<MyClass> GROUP_COMPARATOR = new Comparator<MyClass>() {
@Override
public int compare(MyClass c1, MyClass c2) {
return c1.group.compareTo(c2.group);
}
};
public static List<MyClass> sublist(List<MyClass> list, String group) {
ArrayList<MyClass> ret = new ArrayList<MyClass>();
for (MyClass mc : list)
if (mc.group.equals(group))
ret.add(mc);
return ret;
}
public static void main(String[] argv) {
ArrayList<MyClass> sorted = new ArrayList<MyClass>();
ArrayList<MyClass> list = new ArrayList<MyClass>();
list.add(new MyClass("A", "5"));
list.add(new MyClass("B", "9"));
list.add(new MyClass("B", "1"));
Collections.sort(list, TITLE_COMPARATOR);
Hashtable<String, Boolean> visited = new Hashtable<String, Boolean>();
for (MyClass mc : list) {
if (visited.get(mc.group) == null) {
List<MyClass> sublist = sublist(list, mc.group);
Collections.sort(sublist, GROUP_COMPARATOR);
sorted.addAll(sublist);
visited.put(mc.group, Boolean.TRUE);
}
}
for (MyClass mc : sorted)
System.out.println(mc.group + " " + mc.title);
}
}
回答2:
what's the proper way to primarily sort by title but make sure groups are "groupped" together as well?
To sort by title and then by group, just switch getGroup()
and getTitle()
everywhere in your comparator.
Here is an alternative, simplified, version:
int compare(MyClass c1, MyClass c2)
{
int cmp = c1.getTitle().compareTo(c2.getTitle());
if (cmp == 0) {
cmp = c1.getGroup().compareTo(c2.getGroup());
}
return cmp;
}
If that's not what you are trying to achieve, please clarify your requirements.
回答3:
Your question makes no sense: Being "grouped together" means sorting by group first, then by title.
There's just no getting around it.
I think you really want what you already coded.
回答4:
Try using .getGroup instead of .getTitle (and vice-versa) in your Comparator. I think you just should do what you're doing the other way around.
来源:https://stackoverflow.com/questions/9064432/proper-way-for-two-way-sorting