tags:

views:

894

answers:

6
+1  Q: 

Java iterator

I am a newbie, I have a question.

I have a map. I have to loop through the map and build the iterator.

Example:

public Iterable<Test> getTests(Map<String, Test> testMap,
    Set<String> strings)
{
    //loop tru the set of strings and build iterator.
    for(final String test1 : strings)
    {

       Test test = testMap.get(test1);

       //build a iterator. not a list.
    }

    return iterator
}

How can I do this?

+1  A: 

Since Collection extends Iterable, the correct solution would be to add the tests to some sort of collection, like an ArrayList.

Collection<Test> tests = new ArrayList<Test>();
for (String key : strings) {
  Test t = testMap.get(key);
  if (t != null)
    tests.add(t);
}
return tests;
erickson
+5  A: 

First of all, your method is returning an Iterable, not an Iterator. Map, Set, and List all implement Iterable, so it might be easier than you think.

Second, an Iterable is merely a class that has an iterator() method which returns an Iterator.

So I would simply build a List of the results and then return it. If you really want to return an Iterator, I would instead call iterator() on the list and return that.

Michael Myers
A: 

An Iterable is something different from an Iterator. An Iterable is something you can iterate through, like a List. You use an Iterator for that. Your questions is not clear about what you want to return from getTests().

Your best shot would be to create an Iterable (like a List or Vector) and return that, or return its Iterator.

nojevive
+3  A: 

Skipping over your Iterator/Iterable confusion (and Iterable is basically an Iterator factory... so you need to write an Iterator either way), I think you mean something like this:

Iterator<Test> getTests(final Map<String,Test> testMap, final Set<String> strings) {
    return new Iterator<Test>() {
      private final Iterator<String> keyIter = strings.iterator();
      private String lastKey;
      public boolean hasNext() { return keyIter.hasNext(); }
      public Test next() { lastKey = keyIter.next(); return testMap.get(lastKey); }
      public void remove() { testMap.remove(lastKey); }
    };
  }

And if you want to return an Iterable, well, that just has to be a factory for those:

Iterable<Test> getTests(final Map<String,Test> testMap, final Set<String> strings) {
    return new Iterable<Test>() {
        public Iterator<Test> iterator() {
            return new Iterator<Test>() {
                private final Iterator<String> keyIter = strings.iterator();
                private String lastKey;
                public boolean hasNext() { return keyIter.hasNext(); }
                public Test next() { lastKey = keyIter.next(); return testMap.get(lastKey); }
                public void remove() { testMap.remove(lastKey); }
              };
        }
    };
}

For extra credit, you can parameterise this method itself and have a generic way of iterating over a selection from a map:

Map<String, Action> map;
Set<String> keys;
for (Action x : filterMap(map, keys)) {
}
araqnid
The lazy iterator way... I thought of that, but was too lazy to actually write it. :P
Michael Myers
remove() should probably remove the Test from the Map (either that or throw UnsupportedOperationException). It should not modify the passed-in Set. In fact, you should almost certainly make a copy of the passed-in Set.
NamshubWriter
Yes, I was trying to get too clever and probably shouldn't have tried to support remove().I think it's fair to leave copying the passed-in set as the caller's responsibility. Without knowing how this is actually going to be used, it's hard to say, but if the results are just used to quickly loop over the map once then duplicating the keys is excessive.
araqnid
+1  A: 

If you want to really return Iterable simplest way is this

public Iterable<Test> getTests(Map<String, Test> testMap, Set<String> strings)
{
   testMap = new HashMap<String, Test>(testMap);
   testMap.keySet().retainAll(strings);
   return testMap.values();
}

If you want to return an iterator, replace the last line with

return testMap.values().iterator();

If you don't care about modifications to the passed in map, skip the initial temp map construction.

EDIT: removed use of clone on the Map interface which doesn't have it.

Jherico
Map doesn't have a public clone() method, does it?
Michael Myers
The Map interface makes no requirement that it's Cloneable. So assuming the passed in testMap has a public clone() is not safe.
Steve Kuo
A: 

As a stab in the dark, what you may be looking for is Map.entrySet.iterator(). It allows you to iterate over the entries of the map.

Note: I know this is not an answer to the OP's question, but it's my guess at answering what they are actually looking for. If this guess turns out to be wrong, I'll delete this answer again to spare people the confusion.

Zarkonnen