1

I'm trying to sort a list of music by revelance corresponding to a list of criteria.

public class Music implements Comparable<CriteriaList> {
    private String genre, artist, album, titre, price, note; 
    // getters, setters
    public int compareTo(CriteriaList list) {
        boolean title, album, genre, artist, note;
        title = !list.getTitle().isEmpty() && this.getTitre().equals(list.getTitle());
        album = !list.getAlbum().isEmpty() && this.getAlbum().equals(list.getAlbum());
        genre = !list.getGenre().isEmpty() && this.getGenre().equals(list.getGenre());
        artist = !list.getArtist().isEmpty() && this.getArtist().equals(list.getArtist());
        note = !list.getNote().isEmpty() && (Integer.parseInt(this.getNote()) >= Integer.parseInt(list.getNote()));
        return ((title ? 1 : 0) + (album ? 1 : 0) + (genre ? 1 : 0) + (artist ? 1 : 0) + (note ? 1 : 0));
    }
}

My function compareTo return the number of fields which match to the criteria list and test if input are not empty.

public class MusicProvider extends Agent {
    public List<Music> getMusicsByCL(CriteriaList list) {
        ArrayList<Music> res = new ArrayList<Music>();
        int[] revelanceTab = new int[res.size()];
        int i = 0, revelance;
        for (Music music : musicListAvailable) {
            revelance = music.compareTo(list);
            if (revelance > 1) {
                res.add(music);
                revelanceTab[++i] = revelance;
            }
        }
        // sort res with revelanceTab
        return res;
    }
}

Here I want to retrieve musics with a minimun revelance of 1 and sort them by revelance. How can I do that ?

3 Answers 3

4

Assuming you have already created the functionality to actually calculate the relevance, I would proceed like this.

Create a simple class to hold the Music and the calculated relevance score, just pass in the Criteria and store the result of the calculation.

public class ScoredMusic {
    private int relevanceScore;
    public ScoredMusic(Music m) { ... }
    public void calculateRelevance(Criteria criteria) { ... }
    public Music getMusic() { ... }
    public int getRelevanceScore() { ... }
}

Then I would score all the Music instances you have, store them in a list, and do a very simple compareTo() implementation that simply compares the relevanceScore between each ScoredMusic instance.

Sign up to request clarification or add additional context in comments.

Comments

1

Comparable is used to compare two instances of Music against each other. If you want to compare to an external entity, use a Comparator implementation and pass it to Collections.sort(List, Comparator). The Comparator would need to be initialized with the CriteriaList and the compare method would return a positive number if the first element should be ranked higher, negative number if the second element should be ranked higher, or 0 if they are equivalent. In your example, you would use your compareTo method and subtract the second element's score from the first and return that.

Something like this:

import java.util.Comparator;

public class MusicComparator implements Comparator<Music> {

    private final CriteriaList criteria;

    public MusicComparator(CriteriaList criteria) {
        this.criteria = criteria;
    }
    @Override
    public int compare(Music o1, Music o2) {
        return score(o1) - score(o2);
    }

    private int score(Music music) {
        boolean title, album, genre, artist, note;
        title = criteria.getTitle().isEmpty() || criteria.getTitle().equals(music.getTitle());
        album = criteria.getAlbum().isEmpty() || criteria.getAlbum().equals(music.getAlbum());
        genre = criteria.getGenre().isEmpty() || criteria.getGenre().equals(music.getGenre());
        artist = criteria.getArtist().isEmpty() || criteria.getArtist().equals(music.getArtist());
        note = criteria.getNote().isEmpty() || (!music.getNote().isEmpty() && Integer.parseInt(music.getNote()) >= Integer.parseInt(criteria.getNote()));
        return ((title ? 1 : 0) + (album ? 1 : 0) + (genre ? 1 : 0) + (artist ? 1 : 0) + (note ? 1 : 0));
    }
}

By the way, the isEmpty() methods will not protect you from null pointer exceptions. You will need a better method of handling those if the fields are allowed to be null.

2 Comments

I can add null != criteria.getTitle() && !criteria.getTitle().isEmpty() for each field to protect my function from null pointer exc.
Another option would be to import a StringUtils class. They usually offer an isEmpty or isBlank method to which you can pass your field. There are many options to chose from depending on how you want to handle nulls and blank strings (in case you wanted to treat them differently). There is some overhead involved with importing those packages, but they offer many useful features. Apache Commons and Google Guava are good starting points for those types of helper functions.
0

This is my final class,

public class ScoredMusic implements Comparable<ScoredMusic> {
    private int revelanceScore = 0;
    private Music music;

    public ScoredMusic(Music music, CriteriaList crit) {
        this.music = music;
        calculateRevelance(crit);
    }

    private void calculateRevelance(CriteriaList list) {
        boolean title, album, genre, artist, note;
        title = !list.getTitle().isEmpty() && music.getTitre().equals(list.getTitle());
        album = !list.getAlbum().isEmpty() && music.getAlbum().equals(list.getAlbum());
        genre = !list.getGenre().isEmpty() && music.getGenre().equals(list.getGenre());
        artist = !list.getArtist().isEmpty() && music.getArtist().equals(list.getArtist());
        note = !list.getNote().isEmpty() && (Integer.parseInt(music.getNote()) >= Integer.parseInt(list.getNote()));
        revelanceScore = ((title ? 1 : 0) + (album ? 1 : 0) + (genre ? 1 : 0) + (artist ? 1 : 0) + (note ? 1 : 0));
    }

    public Music getMusic() {
        return music;
    }

    public int getRevelanceScore() {
        return revelanceScore;
    }

    public int compareTo(ScoredMusic other) {
        return Integer.compare(this.getRevelanceScore(), other.getRevelanceScore());
    }
}

and in my second class

public List<ScoredMusic> getMusicsScoredByCL(CriteriaList list) {
    ArrayList<ScoredMusic> scoredMusics = new ArrayList<ScoredMusic>();
    ScoredMusic sc;
    for (Music music : musicListAvailable) {
        sc = new ScoredMusic(music, list);
        scoredMusics.add(sc);
    }
    // sort by revelance and descending order
    Collections.sort(scoredMusics, Collections.reverseOrder());
    return scoredMusics;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.