简体   繁体   English

使用ListIterator在Java中的LinkedList上来回移动

[英]Using ListIterator to move back and forth over a LinkedList in Java

I have a LinkedList over which I need to iterate back and forth multiple times. 我有一个LinkedList,我需要多次来回迭代。 I am using it to keep track of a series of pages in a workflow that will be created dynamically. 我正在使用它来跟踪将动态创建的工作流中的一系列页面。 This does not behave as I would expect. 这并不像我期望的那样。 Given this example: 鉴于这个例子:

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

I thought perhaps I was building my list incorrectly, or using the Iterator wrong, but after reading the documentation, this seems to be by design: 我想也许我正在错误地构建我的列表,或者使用Iterator错误,但在阅读文档之后,这似乎是设计的:

A ListIterator has no current element; ListIterator没有当前元素; its cursor position always lies between the element that would be returned by a call to previous() and the element that would be returned by a call to next(). 它的光标位置总是位于调用previous()返回的元素和调用next()返回的元素之间。

And: 和:

(Next) Returns the next element in the list. (Next)返回列表中的下一个元素。 This method may be called repeatedly to iterate through the list, or intermixed with calls to previous to go back and forth. 可以重复调用此方法以遍历列表,或者与之前的调用混合以来回传递。 (Note that alternating calls to next and previous will return the same element repeatedly.) (请注意,对next和previous的交替调用将重复返回相同的元素。)

So after reading this, it is clear why my code is behaving the way it does. 因此,在阅读本文之后,很明显为什么我的代码的行为方式如此。 I just don't understand why it should work this way. 我只是不明白为什么它应该这样工作。 Even remove seems to be bending over backwards to accommodate this implementation: 甚至删除似乎是向后弯曲以适应这种实现:

Note that the remove() and set(Object) methods are not defined in terms of the cursor position; 请注意,remove()和set(Object)方法没有根据光标位置定义; they are defined to operate on the last element returned by a call to next() or previous(). 它们被定义为对next()或previous()调用返回的最后一个元素进行操作。

Conceptually, a LinkedList seemed to model my workflow cases pretty well, but I can't use an Iterator that behaves this way. 从概念上讲,LinkedList似乎很好地模拟了我的工作流程案例,但我不能使用行为方式的迭代器。 Am I missing something here, or should I just write my own class maintain a list of cases and navigate through them? 我在这里遗漏了什么,或者我应该写自己的班级来维护案例列表并浏览它们?

This should do your job: 这应该做你的工作:

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

    }   
}

And a fiddle for it. 这是一个小提琴

ListIterator was designed to behave this way. ListIterator旨在以这种方式运行。 See the conversation beneath ShyJ's answer for the rationale. 请参阅ShyJ答案下的对话理由。

I find this behavior to be beyond idiotic, and have instead written a very simple alternative. 我发现这种行为超出了愚蠢的行为,而是编写了一个非常简单的替代方案。 Here's the Kotlin code with a extension function for ArrayLists: 这是带有ArrayLists扩展功能的Kotlin代码:

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)

If you wish to include removal functionality, I highly recommend writing the API to explicitly instruct the iterator if it should remove left or right, eg by defining those methods as removeNext() and removePrevious() . 如果您希望包含删除功能,我强烈建议编写API以显式指示迭代器是否应该向左或向右删除,例如通过将这些方法定义为removeNext()removePrevious()

Do something like this (pseudocode) -- 做这样的事(伪代码) -

class SkipIterator extends ListIterator {

    public E previous(){
        E n = super.previous();
        return super.previous();
    }

    ...

}

then: 然后:

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

Cheers 干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM