tags:

views:

78

answers:

4

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...

+3  A: 

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
The problem is that i cant sort directly my list of Publication, as i dont have my Vote in this list.
@kevinb92: see my answer for example of how you can use `Comparator` to sort based on an extrinsic criteria.
polygenelubricants
To complete, if you want to change the order depending on what criteria you want to use (date, title, number of vote...) you just have to implement a comparator for each criteria.
Vinze
+3  A: 

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.

Eyal Schneider
+1 on the immutability of anything used as a key to a map. And as said in an other question, the sort function will have to be called each time the order criteria is changed (new votes in this case).
Vinze
+3  A: 

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)
polygenelubricants
'Tally' is a good word :).
Andrew Aylett
A: 

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.

DaveJohnston
This strikes me as a bad idea. Let `Publication` be oblivious to how many `Vote` it gets. It should be made immutable if possible. Such statistical metric is a volatile external measurement that is not intrinsic to `Publication` itself.
polygenelubricants