views:

82

answers:

2

Hello everyone.

I still have a question about Enumerations. Here's a quick sketch of the situation. I have a class Backpack that has a Hashmap content with as keys a variable of type long, and as value an ArrayList with Items. I have to write an Enumeration that iterates over the content of a Backpack. But here's the catch: in a Backpack, there can also be another Backpack. And the Enumeration should also be able to iterate over the content of a backpack that is in the backpack. (I hope you can follow, I'm not really good at explaining..)

Here is the code I have:

public Enumeration<Object> getEnumeration() {
    return new Enumeration<Object>() {
        private int itemsDone = 0;
        //I make a new array with all the values of the HashMap, so I can use
        //them in nextElement()
        Collection<Long> keysCollection = getContent().keySet();            
        Long [] keys = keysCollection.toArray(new Long[keysCollection.size()]);

        public boolean hasMoreElements() {
            if(itemsDone < getContent().size()) {
                return true;
            }else {
                return false;
            }

        }

        public Object nextElement() {               
            ArrayList<Item> temporaryList= getContent().get(keys[itemsDone]);
            for(int i = 0; i < temporaryList.size(); i++) {
                if(temporaryList.get(i) instanceof Backpack) {
                    return temporaryList.get(i).getEnumeration();                       
                }else {
                    return getContent().get(keys[itemsDone++]);
                }
            }
        }
    };

Will this code work decently? It's just the "return temporaryList.get(i).getEnumeration();" I'm worried about. Will the users still be able to use just the hasMoreElemens() and nextElement() like he would normally do?

Any help is appreciated,

Harm De Weirdt

+1  A: 

If it was for practical purposes and not homework, I would use the Iterator interface instead of the old Enumeration. For iterators you have some nice utilities in the apache collections project.

Secondly, your solution seems to have a bug. The method nextElement() should return the elements themselves, but the line return temporaryList.get(i).getEnumeration() returns an Enumeration object instead.

--EDIT--

polygenelubricants suggested a nice, elegant solution. I thought of something else. You can implement a generic ChainEnumeration class (implements Enumeration), that receives a list of Enumerations and allows enumerating the underlying items. In your tree structure, return a simple enumeration with one item for leafs, and a chain enumeration of inner nodes.

The implementation of ChainEnumeration is simple: it manages a list of iterators, plus a reference to the current active iterator, where items are taken from.

Eyal Schneider
That's the whole point of my question. I need to find a way so i can iterate trough possible backpacks in backpacks.So this code won't do that? Can you suggest a way so it would work?
Harm De Weirdt
@Harm De Weirdt: see the text I added to my response. I hope it helps.
Eyal Schneider
What do you mean by "that receives a list of Enumerations". Where do I get the enumerations for that list? Since I only get one extra enumeration at a time, and only when I encounter a backpack in my original iterator. And how should I construct a tree structure? Use my first backpack as a node and underlying backpacks as leafs?
Harm De Weirdt
+1  A: 

You need to create a Stack<Enumeration<Object>>. When you see another Backpack, you push a new Enumeration on that element into the Stack. You always nextElement() from the top of the stack. If the top element is empty, you pop it off. Repeat until the Stack.isEmpty().


Another perhaps simpler technique (depending on how comfortable you are with recursion) is to use "inner" enumerations, which itself can have inner enumerations. Here's a code sample using Iterator on Object[]. It recursively iterates into any nested Object[].

public class RecursiveIterator implements Iterator<Object> {
    final Object[] arr;
    int index = 0;
    Iterator<Object> inner;
    RecursiveIterator(Object[] arr) {
        this.arr = arr;
    }
    @Override public boolean hasNext() {
        while (true) {
            if (inner != null) {
                if (inner.hasNext()) {
                    return true;
                } else {
                    inner = null;
                    index++;
                }
            }
            if (index == arr.length) return false;
            if (arr[index] instanceof Object[]) {
                inner = new RecursiveIterator((Object[]) arr[index]);
            } else {
                return true;
            }
        }
    }
    @Override public Object next() {
        if (!hasNext()) throw new NoSuchElementException();
        return (inner != null) ? inner.next() : arr[index++];
    }
    @Override public void remove() {
        throw new UnsupportedOperationException();
    }       
}

Here's a test harness:

static void dump(Object[] arr) {
    Iterator<Object> iter = new RecursiveIterator(arr);
    while (iter.hasNext()) {
        System.out.print(iter.next() + " ");
    }
    System.out.println("(done)");
}
public static void main(String[] args) throws FileNotFoundException {
    dump(new Object[] {
        1,
        2,
        new Object[] {
            3,
            new Object[] { 4 },
            5,
        },
        6,
        new Object[] {},
        7,
    });
    dump(new Object[] {
        new Object[] {},
        new Object[] {
            new Object[] {          
                new Object[] {},
            },
        },
        new Object[] {},
        new Object[] { null },
    });
}

This prints:

1 2 3 4 5 6 7 (done)
null (done)
polygenelubricants
Is this what you mean?1)First I create a new Stack<Enumeration<Object>>. 2)When I encounter a backpack, I do stack.push(backpack.getEnumeration()) Here is where I can't exactly follow. The previous things are all done in the nextElement() method I presume? But then how are the already iterated objects and the ones that havent been iterated yet "saved"? (I'm sorry for bad sentences and such, but my English isn't that good)Could you provide a bit of sample code? I can't really follow step by step how the program would work now.
Harm De Weirdt
@Harm: I've provided a code sample for a different technique, with inner `Iterator`, which is a bit simpler to implement.
polygenelubricants
Thanks a lot for this example, I'll try to adjust so it works with Enumeration :D
Harm De Weirdt
I'm back, and I managed to get the code to work. (I think, I tested it in my project and it did what it had to)But don't really get how the hasMoreElements() works. In my Javadoc (for the Enumeration with a HashMap<Long, ArrayList<Item>> I placed this:True if there is an inner Enumeration and it has more elements, false if we have reached the end of this HashMap, or if there is atleast one element in the ArrayList. But I don't think that describes the whole method, does it?
Harm De Weirdt
@Harm: I think you can hide the inner working of the recursive enumeration and just say it returns `true` if there's a `nextElement()` and it won't throw `NoSuchElementException`. Internally, yes, a recursive enumeration has a next element if (i) there's an inner that has next, or (ii) there's a next "normal" element at this level.
polygenelubricants