显示单词出现的频率和单词本身

时间:2016-06-30 09:09:38

标签: java collections compareto

这里输入了word并称为容器,它是一个存储字集合。

public class Part1 {

    public static void main(String[] args) {
        WordContainer wc = new WordContainer();
        Scanner in = new Scanner(System.in);
        String line;
        while (in.hasNextLine() && !"stop".equals(line = in.nextLine())) {
            wc.put(new Word(line));
        }

        in.close();
        print();

    }


    public static void print() {
        for (Word w : WordContainer.al) {
            System.out.println(w + ": " + w.getfrequency());
        }
    }
}

存储单词的容器。如果单词在表格中,我们会增加频率,如果不是 - 添加新单词

public class WordContainer {

public static ArrayList<Word> al = new ArrayList<Word>();

public Word put(Word s) {
    for (Word w : al) {
        if (w.s.compareTo(s.getWord()) == 0) {
            s.setfrequency();
        } else {
            al.add(new Word());
        }
    }
    return s;
}

}

存储单词的单词类别及其出现频率

public class Word implements Comparable<Word> {
String s = "";
private int frequency = 0;

Word(String s) {
    this.s = s;
    frequency = 1;
}

Word() {
    setfrequency();
}

public void setfrequency() {
    ++frequency;
}

public int getfrequency() {
    return frequency;
}


public String getWord() {
    return s;
}

    @Override
    public int compareTo(Word o) {
        return s.compareTo(o.getWord());
    }
}

我无法理解为什么它不起作用。 请帮帮我!

3 个答案:

答案 0 :(得分:1)

如果找不到单词,则添加一个新的Word,其中包含空字符串,而不仅仅是作为参数传递的Word(或具有相同内容的副本)。此外,您为每个 Word添加了一个新的Word,其内容不匹配...

此外,增强的for循环尝试在修改后继续遍历列表,从而导致ConcurrentModificationException

此外,您可能希望从列表中返回Word,而不是从参数传递的那个

按如下方式更改代码:

public Word put(Word s) {
    for (Word w : al) {
        if (w.s.compareTo(s.getWord()) == 0) {
            w.setfrequency();

            // found it, now stop searching
            return w;
        }
    }
    // didn't find it; insert
    al.add(s);
    return s;
}

设计说明

我的代码中有几件事我认为设计不好:

  • 您在static中使用了WordContainer列表,但put方法是一种实例方法。这意味着将在WordContainer的所有实例中共享数据,但您需要创建一个实例来调用put。该列表也应该是非static字段。
  • WordContainer类的“内部数据”为public。此外Word是可修改的(您可以在其上调用setfrequency),这可以让您轻松打破封装。解决此问题的最简单方法是将Word类设为WordContainer的内部类,将setfrequency方法更改为private并将String传递给put方法。
public class WordContainer {

    public static class Word implements Comparable<Word> {
        private final String s;
        private int frequency;

        private Word(String s) {
            this.s = s;
            frequency = 1;
        }

        /*Word() {
            this("");
        }*/

        private void setfrequency() {
            ++frequency;
        }

        public int getfrequency() {
            return frequency;
        }


        public String getWord() {
            return s;
        }

        @Override
        public int compareTo(Word o) {
            return s.compareTo(o.getWord());
        }
    }

    private final List<Word> al = new ArrayList<Word>();
    private final List<Word> unmodifiableWords = Collections.unmodifiableList(al);

    public Word put(String s) {
        for (Word w : al) {
            if (w.s.equals(s)) {
                w.setfrequency();
                return w;
            }
        }
        Word word = new Word(s);
        al.add(word);
        return word;
    }

    public List<Word> getWords() {
         // do not allow for external modification of the list
         return unmodifiableWords;
    }

}

答案 1 :(得分:0)

我认为问题在于您班级put中的WordContainer方法。您正在向列表中添加新的Word对象,而不是使用方法中传递的对象。

if (w.s.compareTo(s.getWord()) == 0) {
   s.setfrequency();
} else {
   al.add(new Word());  // This is the likely reason, remove this line
                        // you should not be adding a new object

   al.add(s);           // Try this, you should be adding the object s
}

更新:

您现有的实施需要进行2项更改,之前我没有意识到这一点。

首先,您需要查看您在WordContainer中列出的内容是否已获得该词。如果没有,那么你需要添加它。

第二,要使其正常工作,您需要在Word方法中覆盖equals方法,因为contains方法会尝试使用equals来比较对象

public Word put(Word s) {
        if (al.contains(s)) {
            for (Word w : al) {
                if (w.s.compareTo(s.getWord()) == 0) {
                    s.setfrequency();
                }// else {           //Remove this else, as you add element outside
                 // al.add(s);
                 //}
            }
        } else
            al.add(s);
        return s;
    }

并覆盖equals课程中的Word方法。 Eclipse生成的典型覆盖方法如下所示:

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Word other = (Word) obj;
        if (frequency != other.frequency)
            return false;
        if (s == null) {
            if (other.s != null)
                return false;
        } else if (!s.equals(other.s))
            return false;
        return true;
    }

更新2:

Fabian的答案是一种很好而优雅的方式。

答案 2 :(得分:0)

这是我拍摄的一个问题。我认为问题在于WordContainer put方法。

public class WordContainer {

public static ArrayList<Word> al = new ArrayList<Word>();
public Word put(Word s) {
    for (Word w : al) {
        if (w.s.compareTo(s.getWord()) == 0) {
            //s.setfrequency();
            w.setfrequency(); // <-- set frequency of existing word in al
            return w; // <-- return word object that is in al
        }
        // no need to add new word to list after every failed comparison 
        // unless that's what you want to do.
    }
    al.add(s);
    return s;
}