Рекурсивное перечисление в Java - PullRequest
2 голосов
/ 30 мая 2010

У меня все еще есть вопрос о Перечислениях. Вот быстрый набросок ситуации. У меня есть класс Backpack, который имеет содержимое Hashmap с ключами переменной типа long и значением ArrayList с Items. Я должен написать перечисление, которое перебирает содержимое рюкзака. Но тут есть одна загвоздка: в рюкзаке также может быть другой рюкзак. И Перечисление должно также иметь возможность перебирать содержимое рюкзака, который находится в рюкзаке. (Я надеюсь, что вы можете следовать, я не очень хорошо объясню ..)

Вот код, который у меня есть:

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++]);
                }
            }
        }
    };

Будет ли этот код работать прилично? Это всего лишь «returntimeList.get (i) .getEnumeration ();» Я волнуюсь о. Смогут ли пользователи по-прежнему использовать только hasMoreElemens () и nextElement (), как он это обычно делает?

Любая помощь приветствуется,

Harm De Weirdt

Ответы [ 2 ]

2 голосов
/ 30 мая 2010

Вам необходимо создать Stack<Enumeration<Object>>. Когда вы видите другой Backpack, вы push новый Enumeration на этом элементе в Stack. Вы всегда nextElement() с вершины стека. Если верхний элемент пуст, вы его отключаете. Повторять до тех пор, пока Stack.isEmpty().


Другой, возможно, более простой метод (в зависимости от того, насколько вам удобно с рекурсией) - это использовать «внутренние» перечисления, которые сами по себе могут иметь внутренние перечисления. Вот пример кода с использованием Iterator на Object[]. Он рекурсивно перебирает любые вложенные 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();
    }       
}

Вот тестовый жгут:

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 },
    });
}

Это печатает:

1 2 3 4 5 6 7 (done)
null (done)
1 голос
/ 30 мая 2010

Если бы это было для практических целей, а не для домашней работы, я бы использовал интерфейс Итератор вместо старого Перечисление . Для итераторов у вас есть хороших утилит в проекте Apache collection.

Во-вторых, ваше решение, похоже, содержит ошибку. Метод nextElement () должен возвращать сами элементы, но строка return временныйList.get (i) .getEnumeration () вместо этого возвращает объект Enumeration.

- EDIT -

полигенасмазочные материалы предложили хорошее, элегантное решение. Я думал о чем-то еще. Вы можете реализовать универсальный класс ChainEnumeration (реализует перечисление), который получает список перечислений и позволяет перечислять базовые элементы. В вашей древовидной структуре верните простое перечисление с одним элементом для листьев и цепочечное перечисление внутренних узлов.

Реализация ChainEnumeration проста: он управляет списком итераторов, а также ссылкой на текущий активный итератор, откуда берутся элементы.

...