Использование ListIterator для перемещения вперед и назад по LinkedList в Java
У меня есть LinkedList, над которым мне нужно многократно повторять и повторять. Я использую его для отслеживания серии страниц в рабочем процессе, который будет создан динамически. Это не ведет себя так, как я ожидал. В этом примере:
LinkedList<String> navigationCases;
navigationCases.add("page1");
navigationCases.add("page2");
navigationCases.add("page3");
navigationCases.add("page4");
ListIterator navigationItr = navigationCases.listIterator();
navigationItr.next(); // Returns page1
navigationItr.next(); // Returns page2
navigationItr.previous(); //Returns page2 again
navigationItr.next(); //Returns page2 again
Я подумал, что, возможно, я неправильно создавал свой список или неправильно использовал Iterator, но после прочтения документации это выглядит по дизайну:
У ListIterator нет текущего элемента; его позиция курсора всегда лежит между элементом, который будет возвращен вызовом previous() и элементом, который будет возвращен вызовом next().
и
(Далее) Возвращает следующий элемент в списке. Этот метод можно многократно вызывать, чтобы перебирать список или смешивать с вызовами предыдущего, чтобы идти туда и обратно. (Обратите внимание, что чередующиеся вызовы следующего и предыдущего будут возвращать один и тот же элемент повторно.)
Итак, после прочтения этого, понятно, почему мой код ведет себя так, как он делает. Я просто не понимаю, почему так должно работать. Даже удаление, похоже, сгибается назад, чтобы выполнить эту реализацию:
Обратите внимание, что методы remove() и set (Object) не определены в терминах позиции курсора; они определены для работы с последним элементом, возвращаемым вызовом next() или previous().
Концептуально, LinkedList, похоже, очень хорошо моделировал мои рабочие процессы, но я не могу использовать Iterator, который ведет себя таким образом. Я что-то пропустил здесь или должен просто написать свой собственный класс, поддерживающий список дел и перемещающийся через них?
Ответы
Ответ 1
Это должно выполнить вашу работу:
public class Main {
public static void main(String[] args) {
final LinkedList<String> list = new LinkedList<String> ();
list.add ("1"); list.add ("2"); list.add ("3"); list.add ("4");
final MyIterator<String> it = new MyIterator (list.listIterator());
System.out.println(it.next());
System.out.println(it.next ());
System.out.println(it.next ());
System.out.println(it.previous ());
System.out.println(it.previous ());
System.out.println(it.next ());
}
public static class MyIterator<T> {
private final ListIterator<T> listIterator;
private boolean nextWasCalled = false;
private boolean previousWasCalled = false;
public MyIterator(ListIterator<T> listIterator) {
this.listIterator = listIterator;
}
public T next() {
nextWasCalled = true;
if (previousWasCalled) {
previousWasCalled = false;
listIterator.next ();
}
return listIterator.next ();
}
public T previous() {
if (nextWasCalled) {
listIterator.previous();
nextWasCalled = false;
}
previousWasCalled = true;
return listIterator.previous();
}
}
}
И скрипка для этого.
Ответ 2
ListIterator был разработан таким образом. См. Разговор под ответом ShyJ для обоснования.
Я считаю, что это поведение не должно быть идиотским, и вместо этого написало очень простую альтернативу. Здесь код Котлина с функцией расширения для ArrayLists:
class ListIterator<E>(var list: ArrayList<E>) : Iterator<E> {
private var cursor: Int = 0
fun replace(newList: ArrayList<E>) {
list = newList
cursor = 0
}
override fun hasNext(): Boolean {
return cursor + 1 < list.size
}
override fun next(): E {
cursor++
return current()
}
fun hasPrevious(): Boolean {
return 0 <= cursor - 1
}
fun previous(): E {
cursor--
return current()
}
fun current(): E {
return list[cursor]
}
}
fun <E> ArrayList<E>.listFlippingIterator() = ListIterator(this)
Если вы хотите включить функцию удаления, я настоятельно рекомендую написать API для явного указания итератора, если он должен удалить левый или правый, например. определяя эти методы как removeNext()
и removePrevious()
.
Ответ 3
Сделайте что-нибудь вроде этого (псевдокод) -
class SkipIterator extends ListIterator {
public E previous(){
E n = super.previous();
return super.previous();
}
...
}
то
LinkedList<String> navigationCases;
navigationCases.add("page1");
navigationCases.add("page2");
navigationCases.add("page3");
navigationCases.add("page4");
SkipIterator navigationItr = (SkipIterator)navigationCases.listIterator();
navigationItr.next(); // Returns page1
navigationItr.next(); // Returns page2
navigationItr.previous(); // Returns page1
Приветствия