0

I have an ArrayList of a custom class Highscore The array list contains multiple Highscore's

As shown in the code below, there is a duplicate entry. That being, highscores.add(new Highscore("user 1", 25)); When I say duplicate, I mean the same String (username) and int (score) value

I want to be able to detect it so that only 1 of those entries stays in the ArrayList

Code:

ArrayList<Highscore> highscores = new ArrayList<>();
highscores.add(new Highscore("user 1", 25));
highscores.add(new Highscore("user 2", 10));
highscores.add(new Highscore("user 3", 55));
highscores.add(new Highscore("user 1", 25));
highscores.add(new Highscore("user 2", 5));
highscores.add(new Highscore("user 3", 30));

Highscore:

public class Highscore implements ConfigurationSerializable {

    String username;
    public int score;

    public Highscore(String username, int score) {
        this.username = username;
        this.score = score;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public Map<String, Object> serialize() {
        Map<String, Object> mappedObject = new LinkedHashMap<String, Object>();
        mappedObject.put("username", username);
        mappedObject.put("score", score);
        return mappedObject;
    }

    public static Highscore deserialize(Map<String, Object> mappedObject) {
        return new Highscore((String) mappedObject.get("username"),
                (int) mappedObject.get("score"));
    }
}

I have seen some people suggest using a HashSet or LinkedHashSet, but in my case, that doesn't work as it identifies duplicates based on the id of the Highscore, which is always different.

Thanks in advance :)

Luke C
  • 140
  • 2
  • 12

1 Answers1

2

I have seen some people suggest using a HashSet or LinkedHashSet, but in my case, that doesn't work as it identifies duplicates based on the id of the Highscore, which is always different.

You define what "similiar" means by overriding equals (and hashCode) methods. For extensive explanation see this.

If your requirement is to not allow duplicates based on properties of your class - Set is a good choice. For example HashSet. You will have to override equals and hashCode methods :

class Highscore {

    private String username;
    public int score;

    //getters setters constructors

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Highscore highscore = (Highscore) o;
        return score == highscore.score &&
                Objects.equals(username, highscore.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(username, score);
    }
}

And then :

Set<Highscore> highscores = new HashSet<>();

highscores.add(new Highscore("user 1", 25));
highscores.add(new Highscore("user 2", 10));
highscores.add(new Highscore("user 3", 55));
highscores.add(new Highscore("user 1", 25));
highscores.add(new Highscore("user 2", 5));
highscores.add(new Highscore("user 3", 30));

System.out.println(highscores.size());

Will print 5 and the duplicate entry is not added. If you want to preserve order of insertion use LinkedHashSet.

Of course you could also use your ArrayList and remove elements by calling List::remove(object) but it uses equals to compare objects underneath too. I think that using Set here is advisable.

Michał Krzywański
  • 15,659
  • 4
  • 36
  • 63