【问题标题】:Not allowing duplicates of an object in an Array List不允许在数组列表中重复对象
【发布时间】:2020-01-05 04:24:52
【问题描述】:

我目前正在用 Java 开发一个家族世仇游戏。我有一个名为问题的对象问题的数组列表,它存储随机问题以在整个游戏中使用。我正在尝试以某种方式填充数组列表以确保没有重复项,但是它不起作用并且我得到了重复项。

初始化为字段是我的问题数组列表:

private ArrayList<Question> questions = new ArrayList<>();

这是我目前正在尝试的:

//Populates questions list
        for(int i=0; i<15; i++)
        {
           Question q = new Question();
           //makes sure there are no duplicates
            if(!questions.contains(q))
                questions.add(q); //not working for some reason cry

           System.out.println(q.getQuestion());
        }

当我打印出问题时,我仍然得到重复:

Name something you would see on the Jerry Springer show:
Name something that would get you thrown out of most bars:
What accent might an American pretend to have in order to sound more attractive:
Name a breed of dog that might be used as a guard dog:
Name a place where a child might get seperated from its parents:
Name something you would see on the Jerry Springer show:
Name something that would get you thrown out of most bars:
Name a place where a child might get seperated from its parents:
Name something for which you need a warranty:
Name a game that would be inappropriate at a company party:
Name something for which you need a warranty:
Name a place where a child might get seperated from its parents:
Name an activity that could be rained out:
Name something for which you need a warranty:
Name something that would get you thrown out of most bars:

我确实在我的问题类中覆盖了 equals 方法,但它并没有起到作用。这是我的问题类:

/**
 * Question proposed to players to guess one of the answers on the board
 *
 * Each question has 5 possible answers
 *
 * The top answer to each question is stored at Answers(0) and is worth the most
 * The last answer is stored at Answers(4) and is worth the least
 *
 *
 * @author Stefan Gligorevic
 */
import java.util.ArrayList;
import java.util.Random;
import java.lang.String;
import java.lang.Object;

public class Question {

    private ArrayList<Answer> answers;
    private String question;

    /**** MIGHT HAVE TO INITIALIZE ANSWERS TO AN ARRAY LIST WITH NO SIZE SO ADD CAN WORK ****/
    //constructors
    public Question(){
        answers = new ArrayList<>();
        question=getRandomQuestion();
    }

    //makes a random question with a set of answers
    public String getRandomQuestion() {
        String ask = "";

        Random rand = new Random();
        int n = 1 + rand.nextInt(10);

        switch (n)
        {
            case 1:
                ask="Name a place where a child might get seperated from its parents:";
                answers.add(new Answer("Mall", 38));
                answers.add(new Answer("Park", 23));
                answers.add(new Answer("Zoo", 16));
                answers.add(new Answer("Theme Park", 16));
                answers.add(new Answer("Airport", 5));
                break;
            case 2:
                ask="Name something for which you need a warranty:";
                answers.add(new Answer("Car", 54));
                answers.add(new Answer("TV", 23));
                answers.add(new Answer("Watch", 8));
                answers.add(new Answer("Computers", 4));
                answers.add(new Answer("Appliance", 3));
                break;
            case 3:
                ask="Name a fruit you can buy dried:";
                answers.add(new Answer("Grape", 22));
                answers.add(new Answer("Banana", 21));
                answers.add(new Answer("Apricot", 21));
                answers.add(new Answer("Prune", 17));
                answers.add(new Answer("Apple", 15));
                break;
            case 4:
                ask="Name an activity that could be rained out:";
                answers.add(new Answer("Sports Event", 45));
                answers.add(new Answer("Picnic", 34));
                answers.add(new Answer("Wedding", 10));
                answers.add(new Answer("Concert", 7));
                answers.add(new Answer("Barbecue", 3));
                break;
            case 5:
                ask="What accent might an American pretend to have in order to sound more attractive:";
                answers.add(new Answer("French", 61));
                answers.add(new Answer("British", 18));
                answers.add(new Answer("Italian", 8));
                answers.add(new Answer("Spanish", 8));
                answers.add(new Answer("Australian", 3));
                break;
            case 6:
                ask="Name a sport that might be played at a family reunion:";
                answers.add(new Answer("Football", 54));
                answers.add(new Answer("Baseball", 21));
                answers.add(new Answer("Horseshoe", 8));
                answers.add(new Answer("Frisbee", 7));
                answers.add(new Answer("Basketball", 6));
                break;
            case 7:
                ask="Name a game that would be inappropriate at a company party:";
                answers.add(new Answer("Spin the Bottle", 41));
                answers.add(new Answer("Strip Poker", 32));
                answers.add(new Answer("Twister", 11));
                answers.add(new Answer("Truth or Dare", 11));
                answers.add(new Answer("Beer Pong", 3));
                break;
            case 8:
                ask="Name something that would get you thrown out of most bars:";
                answers.add(new Answer("Getting in a fight", 45));
                answers.add(new Answer("Drinking too much", 29));
                answers.add(new Answer("Not Paying", 6));
                answers.add(new Answer("Stripping", 5));
                answers.add(new Answer("Being underage", 3));
                break;
            case 9:
                ask="Name something you would see on the Jerry Springer show:";
                answers.add(new Answer("Fighting", 56));
                answers.add(new Answer("Nudity", 22));
                answers.add(new Answer("Security", 6));
                answers.add(new Answer("Jerry Springer", 4));
                answers.add(new Answer("Chairs Thrown", 3));
                break;
            case 10:
                ask="Name a breed of dog that might be used as a guard dog:";
                answers.add(new Answer("German Shepard", 36));
                answers.add(new Answer("Pit Bull", 23));
                answers.add(new Answer("Doberman Pinscher", 20));
                answers.add(new Answer("Rottweiler", 8));
                answers.add(new Answer("Bulldog", 5));
                break;
            default:
                //won't reach this hehe
        } //end switch
        return ask;
    }

    @Override
    public boolean equals(Object obj)
    {
        if(obj == null)
            return false;

        if(!Question.class.isAssignableFrom(obj.getClass()))
            return false;

        final Question q = (Question) obj;

        if(q.getQuestion() == null || this.getQuestion() == null)
            return false;

        if(!this.getQuestion().equalsIgnoreCase(q.getQuestion()))
            return false;

        return true;
    }

    //getters and setters
    public String getQuestion() { return question; }
    public ArrayList<Answer> getAnswers() { return answers; }

    //returns answer at given index
    public Answer answerAt(int index) { return answers.get(index); }
    //returns String of answer at specified index
    public String getAnswerAt(int index) { return answers.get(index).getAnswer(); }
    //returns point value of answer at specified index
    public int getAnswerPoints(int index) { return answers.get(index).getValue(); }

    //returns the points earned for this question
    //points are the point values of all the answers that have been found
    public int pointsEarned() {
        int points=0;
        for (int i=0; i<answers.size(); i++)
        {
            if(answers.get(i).isFound())
                points += answers.get(i).getValue();
        }
        return points;
    }

    //Sets a particular answer's value
    public void setAnswerVal(int index, int val) { answers.get(index).setValue(val); }

    //Add a multiplier to each answer's value for the question
    public void addMultiplier(int multiplier)
    {
        for(int i=0; i<answers.size(); i++)
        {
            int val = answers.get(i).getValue();
            answers.get(i).setValue(multiplier * val);
        }
    }

    //returns string of each answer
    public String topAnswer() { return answers.get(0).getAnswer(); }
    public String Answer2() { return answers.get(1).getAnswer(); }
    public String Answer3() { return answers.get(2).getAnswer(); }
    public String Answer4() { return answers.get(3).getAnswer(); }
    public String lastAnswer() { return answers.get(4).getAnswer(); }

    //returns values of each answer
    public int topAnswerVal() { return answers.get(0).getValue(); }
    public int Answer2Val() { return answers.get(1).getValue(); }
    public int Answer3Val() { return answers.get(2).getValue(); }
    public int Answer4Val() { return answers.get(3).getValue(); }
    public int lastAnswerVal() { return answers.get(4).getValue(); }

}

我不明白为什么它不起作用 :( 非常感谢帮助!

【问题讨论】:

  • 尝试使用:if(!this.getQuestion().compareTo(q.getQuestion()==0){return false;},或者尝试实现 Comparable 并覆盖 compareTo() 方法跨度>
  • 您显示的输出是否来自//Populates questions list 代码位?如果是这样,那不是您的questions 列表中的内容。你能不能再放一个for 循环来显示列表中的内容?
  • 您正在打印出每一个问题,无论它是否被添加到 ArrayList 中。
  • 这能回答你的问题吗? Remove duplicates from a Java List

标签: java arraylist


【解决方案1】:

您覆盖的 equals 方法逻辑很好。只是您在错误的地方执行sysout 使您相信逻辑不起作用。不要在添加问题的 for 循环中打印问题,而是在该循环之外打印它。如下修改你的逻辑,你会得到预期的结果

    for(int i=0; i<15; i++)
    {
        Question q = new Question();
        //makes sure there are no duplicates
        if(!questions.contains(q))
            questions.add(q); //not working for some reason cry
    }
    for (Question question : questions) {
        System.out.println(question.getQuestion());
    }

注意,无论何时重写 equals 方法,您也应该重写 hashCode。因为如果你不这样做,那么将使用Object 类中的默认实现。因此,即使根据 equals() 方法它们相等,它们也可能具有不同的哈希码。您正在使用Arraylist,因此您不会在这里遇到问题,但是像HashSet, HashMap 这样的一些集合同时使用equalshashcode 来添加和检索对象。这可能会给您带来意想不到的结果。因此,请始终始终如一地覆盖它们。 Link

public int hashCode(){
    return question.hashCode();
    }

此外,如果您的相等逻辑仅基于 String question,我建议您让您的 Question 类实现 Comparable 或为您的 Question 类创建一个 Comparator,而不是使用 @ 987654337@ 保存问题列表,使用Set(TreeSet) 这样1)您不必担心实现equals和hashcode方法,2)您不必总是检查添加新问题。下面是一段代码sn-p

实现Comparable&lt;Question&gt;

@Override
public int compareTo(Question question) {
    return this.getQuestion().compareTo(question.getQuestion());
}

Set添加问题

Set<Question> questions = new TreeSet<>();
    for(int i=0; i<15; i++)
    {
        questions.add(new Question());
    }
    for (Question question : questions) {
        System.out.println(question.getQuestion());
    }

【讨论】:

  • 哎呀,我犯了一个愚蠢的错误。感谢你的建议!现在更有意义了。
【解决方案2】:

当您覆盖equals() 时,您也必须覆盖hashCode()。阅读原因 here.

【讨论】:

  • 虽然这句话是正确的,但它与将对象添加到 ArrayList 无关。 ArrayList 不使用 hashCodes。
  • 我认为它在检查包含时会这样做
【解决方案3】:
Its better to use HashSet(if order of objects is not important)or LinkedHashSet(if 
order of objects is important) using an ArrayList will decrease the performance of the 
game on which you are currently working.
If you want to use LinkedHashSet you have to override hashCode and equals method.

eg program...

import java.util.LinkedHashSet;
public class Question {

    private ArrayList<Answer> answers;
    private String question;

    public Question(){
        answers = new ArrayList<>();
        question=getRandomQuestion();
    }
    @Override
    public int hashCode(){
        return question.hashCode();
    }
    @Override
    public boolean equals(Object o){
            if(o==null)return false;
            if(o.getClass()!=this.getClass())return false;
            Question q=(Question)o;
            return q.question.equals(this.question);
    }
    ...
    </>
    ...
    public static void main(String $[]){
        LinkedHashSet<Question>hash=new LinkedHashSet<>;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    相关资源
    最近更新 更多