Sort an object by an other one
Here's the deal :
I have Publication objets in my application. I also have Vote objet (forOrAgainst,author,linkedPublication)
I want to sort publication by date, title... and also by number of votes开发者_如何学编程.
I cant directly sort my list of publication as i dont have the number of vote in that list. How can i sort my list of publication without adding method to the publication object.
What is the best way to link them ?
Should i return a hashmap ? a treeset ? an array ?
It's kinda messy in my brain now...
Here's an example of using Comparator
to sort based on an external criteria:
import java.util.*;
class VoteComparator implements Comparator<String> {
final Map<String, Integer> tally;
VoteComparator(Map<String, Integer> tally) {
this.tally = tally;
}
@Override public int compare(String pub1, String pub2) {
int v1 = tally.get(pub1);
int v2 = tally.get(pub2);
return
(v1 < v2) ? -1 :
(v1 > v2) ? +1 :
0;
}
};
This uses just String
for publication for simplicity; you'd want to sort Publication
in your application. This also uses a simple int
to get the vote count, but essentially there has to be a tally service that gives you, given a Publication
, what its Vote
count is.
Note: English is not my first language, so perhaps "tally" isn't the right word for it, but basically some sort of vote registrar, vote recorder, essentially a map between an object, and how many votes it gets.
Then you can sort, using, say, TreeSet
.
public class SortExample {
public static void main(String[] args) {
Map<String, Integer> tally = new HashMap<String, Integer>();
tally.put("foo", 42);
tally.put("bar", 13);
tally.put("Fizz", 3);
tally.put("Buzz", 5);
tally.put("FizzBuzz", 15);
Comparator<String> voteComparator = new VoteComparator(tally);
SortedSet<String> sortedByVote = new TreeSet<String>(voteComparator);
sortedByVote.addAll(tally.keySet());
for (String pub: sortedByVote) {
System.out.println(pub + " (" + tally.get(pub) + " votes)");
}
}
}
This prints:
Fizz (3 votes)
Buzz (5 votes)
bar (13 votes)
FizzBuzz (15 votes)
foo (42 votes)
A solution is to implements the interface Comparator (http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html), you can then use for example the Collections.sort(List list, Comparator comparator) function (http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator).
Vinze is right - The usage of a Comparator is recommended here. In your case, the comparator is statefull; at construction time, you have to provide it with data regarding the votes of the different items (since they are not part of the items).
Collections.sort(..) is a good idea if you want to make your list sorted. If on the other hand you decide to put your items into some kind of SortedSet (or SortedMap), make sure that the votes (and other fields used by the comparator) stay unchanged. Otherwise the data structure will become corrupted and will no longer preserve the right order of items.
I would consider a redesign of your class structure to something like:
public class Publication implements Comparable<Publication> {
private String title;
private Date date;
// etc....
private Collection<Vote> votes;
// Possibly even:
private int upVotes;
private int downVotes;
// Constructors etc.
// Handle votes here.
public void addVote(Vote vote) {
votes.add(vote);
if (vote.isUpVote()) {
upVotes++;
} else {
downVotes++;
}
}
// Other methods for handling whatever you need to do.
public int compareTo(Publication other) {
// Now in here you can implement your sorting logic and have direct access to number of votes.
// If you decide not to implement the counters of upVotes and downVotes then you will need to iterate over your votes collection and count them each time you do a compare, so it might be worth doing it to be more efficient. You just have to make sure that any methods you add that affect the votes collection also updates the counters.
}
}
public class Vote {
private boolean isUpVote;
private String author;
// No need for a link to the publication now.
public boolean isUpVote() {
return isUpVote;
}
// etc.
}
Now, wherever you store your publications you can just do:
Collections.sort(publications);
assuming your publications collection is a List, i.e.
List<Publication> publications = new ArrayList<Publication>();
Remember (as Eyal said) if you change the state of your publications (i.e. change votes or anything else that influences the sorting order) then you will have to resort, it won't happen automatically.
精彩评论