Reputation: 329
I have to do a synonyms dictionary using a TreeMap. The TreeMap is of <Word, ArrayList<Word>>
type. That means that for each key represented by a Word there will be a list of synonyms. When I want to list the contents of the dictionary, by using the method below, I discover that the ArrayList returned is null. What can I do? I tried tracing the code but I don't seem to find the error.
The method is :
public String listContent() {
Set set = wordList.keySet();
Iterator it = set.iterator();
String result = new String();
ArrayList<Word> words = new ArrayList<Word>();
while (it.hasNext()) {
Word temp = (Word) it.next();
words = wordList.get(temp);
if (words != null) {
Iterator it2 = words.iterator();
result += temp.getContent();
result += " - ";
int size = words.size();
while (it2.hasNext()) {
result += ((Word) it2.next()).getContent();
if (size != 1)
result += ", ";
size--;
}
result += "\n";
}
}
return result;
}
The ArrayList returned by wordList.get(temp) is null for some of the inserted elements. I checked the watches but there, they're not. What should I do ?
wordList is a TreeMap<Word, ArrayList<Word>>;
EDIT - the addWord method
public void addWord(String content1, String content2)
{
Word w1 = new Word(content1);
Word w2 = new Word(content2);
Set set = wordList.entrySet();
Iterator it = set.iterator();
boolean ok=false;
while(it.hasNext())
{
Map.Entry<Word,ArrayList<Word>> temp = (Map.Entry<Word,ArrayList<Word>>) it.next();
if(temp.getKey().getContent().matches(content1))
{
ArrayList<Word> words = temp.getValue();
Iterator it2 = words.iterator();
if(words.isEmpty()) words.add(w2);
else
{
boolean ok2=true;
while(it2.hasNext())
{
Word tempy = (Word) it2.next();
if(tempy.getContent().equals(content2))
{
ok2=false;
break;
}
}
if(ok2) words.add(w2);
}
ok=true;
}
}
if(!ok) {
ArrayList<Word> tempys = new ArrayList<Word>();
tempys.add(w2);
wordList.put(w1,tempys);
}
}
EDIT 2 - Word Class
public class Word implements Serializable,Comparable {
private String content;
public Word (String content)
{
this.content = content;
}
public void setContent(String content)
{
this.content=content;
}
public String getContent()
{
return content;
}
@Override
public int compareTo(Object o) {
if(((Word)o).getContent().equals(this.getContent())) return 0;
return 1;
}
}
Upvotes: 0
Views: 393
Reputation: 691715
Your compareTo method is wrong. The contract is that if A > B, then you must have B < A. Your implementation always returns 1 if the contents are not equal.
You should implement it like this:
@Override
public int compareTo(Word w) {
return this.content.compareTo(w.content);
}
(and the Word class should implement Comparable<Word>
, not Comparable).
Since a TreeMap uses this method to tell if some word is bigger or smaller than another one, and since the method returns incoherent results, the Map also returns incoherent results.
Upvotes: 2
Reputation: 200148
I've cleaned up your existing code to use proper Java idioms, like for-each loop, StringBuilder instead of concatenating a String, avoid that size--
hack, stuff like that.
public String listContent() {
final StringBuilder result = new StringBuilder();
for (Map.Entry<Word, List<Word>> e : wordList.entrySet()) {
final List<Word> words = e.getValue();
if (words != null) {
result.append(e.getKey().getContent()).append(" - ");
final Iterator<Word> it = words.iterator();
result.append(it.next().getContent());
while(it.hasNext()) result.append(", ").append(it.next().getContent());
result.append("\n");
}
}
return result.toString();
}
Here's also a cleaned-up version of addWord, but still a heavy mess of program logic. If anyone has patience for this, I encourage him to steal and improve on this.
public void addWord(String content1, String content2) {
final Word w1 = new Word(content1), w2 = new Word(content2);
final Set<Map.Entry<Word, List<Word>>> set = wordList.entrySet();
for (Map.Entry<Word, List<Word>> temp : set) {
if (!temp.getKey().getContent().matches(content1)) {
final List<Word> newList = new ArrayList<Word>();
newList.add(w2);
wordList.put(w1,newList);
break;
}
final List<Word> words = temp.getValue();
if (words.isEmpty()) words.add(w2);
else {
for (Word w : words) {
if (w.getContent().equals(content2)) {
words.add(w2);
break;
}
}
}
}
}
Upvotes: 0
Reputation: 3171
The addWord method is a horrible mess and I'm getting a headache when I try to look at it, but my educated guess is that the system does not work because the Word class implements neither the equals
method nor the hashCode
method. Try adding these to it:
@Override
public int hashCode() {
return this.content.hashCode();
}
@Override
public boolean equals(Object o) {
return this.content.equals(o);
}
With those methods the TreeMap and the other structures are able to identify that two instances of Word classes that represent the same word are, indeed, equal.
Upvotes: 0
Reputation: 544
Did you check that when you insert a synonym everything is ok? BTW you should use StringBuilder for concatenating strings (better in perf) and you'd better use worklist.entrySet() for iterating on key and value at the same time, instead of several get and iterators.
Upvotes: 0