views:

194

answers:

2

I'm having difficulty using an inner Iterator.

private List<List<? extends HasWord>> sentences = new ArrayList<List<? extends HasWord>>(); 
private Iterator<String> wordIterator = new Words();
private class Words implements Iterator<String> {

 int currSentence = 0;
 int currWord = 0;

 @Override
 public boolean hasNext() {
  return currSentence != sentences.size() - 1 && currWord != sentences.get(currSentence).size() - 1;
 }

 @Override
 public String next() {
  String nextWord = sentences.get(currSentence).get(currWord).word();
  currSentence++;
  currWord++;

  return nextWord;
 }

 @Override
 public void remove() {
  throw new UnsupportedOperationException();   
 }

}

Then, I try to iterate over it:

for (String s : wordIterator) { //Error: Can only iterate over an array or an instance of java.lang.Iterable
      words.add(s);

But it doesn't work. (See commented compiler error on the problematic line). What am I doing wrong here?

On an engineering note, do is the right way to solve my problem? I have a bunch of loops of this form:

 for (List<? extends HasWord> sent : sentences) {
  for (HasWord token : sent) {
            //do stuff
  }
     }

So I decided an Iterator would be cleaner. Is this overkill, or is there another way you'd do it?

+5  A: 

There's nothing fundamentally wrong with having two nested for loops to do this, but I think this would be cleaner:

public class Words implements Iterator<String> {
  private final Iterator<HasWord> sentences;
  private Iterator<String> currentSentence;

  public boolean hasNext() {
    return currentSentence.hasNext() || sentences.hasNext();
  }

  public String next() {
    if (currentSentence.hasNext()) {
      return currentSentence.next();
    }
    currentSentence = sentences.next();
    return next(); // will return the first word of the next sentence
  }
  //remove() omitted for brevity
}

Return a new instance of this class every time you need an iterator over several sentences, and initialize the sentences field using sentences.iterator();

(Edited after reading your question more carefully)

Jorn
Note that you may have to add some additional checking if sentences can be empty.
Jorn
+2  A: 
private class Words implements Iterator<String>, Iterable<String> {
  ...
  public Iterator<String> iterator() {
    return this;
  }
  ...
}
james