【问题标题】:descendingIterator for java.util.Listjava.util.List 的 descendingIterator
【发布时间】:2017-07-03 08:42:23
【问题描述】:

LinkedList 可以像这样使用升序或降序迭代器进行迭代:

LinkedList<Object> list = new LinkedList<Object>();
   ...
StringJoiner sJ1 = new StringJoiner(" ");
list.iterator().forEachRemaining(a -> sJ1.add(a.toString()));
System.out.println("averse: \n" + sJ1.toString());

StringJoiner sJ2 = new StringJoiner(" ");
list.descendingIterator().forEachRemaining(a -> sJ2.add(a.toString()));
System.out.println("reverse: \n" + sJ2.toString());
averse: 
Hello 2 Chocolate 10
reverse: 
10 Chocolate 2 Hello

descendingIterator 不适用于 ListArrayList。 是否有任何解决方法或在列表说明中,为什么 descendingIteratorList 中不存在?

问题类似于Can one do a for each loop in java in reverse order?。但所有答案都推荐临时解决方案或 3rd 方库。

这可能使用流流吗? (不幸的是,我的谷歌搜索只为流 Java 8 stream reverse order 提供了缺席标准反向)

正如我所提到的,我的问题与流有关,但是:

  • 使用流只是一种选择,问题是关于java.util.Iteratorjava.util.List
  • 对该问题的回答仅解决了部分情况,但显示缺乏方便的一般反向。如果我没有错过术语 List 是有序集合,则对 Comparable 项目进行排序以实现顺序会缩小范围。

【问题讨论】:

  • 也许您只想使用ArrayDeque 而不是ArrayList
  • @Holger ArrayDeque 真的解决了我的问题。但是对我来说,需要这样一个解决方案看起来很尴尬。因为 ArrayDeque 似乎比降序 for 循环更稀有且鲜为人知的工具,并且它没有实现 List。

标签: java arraylist linked-list java-8


【解决方案1】:

List 不能有一个降序迭代器并没有很好的理由。每个List 都需要支持ListIterator,可以使用hasPrevious()previous() 方法以相反的顺序迭代。不过,这似乎是一个相当少见的用例。

这里有一个小实用方法,可以将 Iterable 调整为以相反顺序迭代的 ListIterator

static <T> Iterable<T> descendingIterable(List<? extends T> list) {
    return () -> {
        ListIterator<? extends T> li = list.listIterator(list.size());
        return new Iterator<T>() {
            public boolean hasNext() { return li.hasPrevious(); }
            public T next() { return li.previous(); }
        };
    };
}

您可以使用它来实现您的示例:

List<String> list = Arrays.asList("Hello", "2", "Chocolate", "10");
StringJoiner sj = new StringJoiner(" ");
descendingIterable(list).iterator().forEachRemaining(sj::add);
System.out.println(sj);

10 Chocolate 2 Hello

或者你可以在增强的for循环中使用它:

for (String s : descendingIterable(list)) {
    System.out.println(s);
}

10
Chocolate
2
Hello

我最初创建了一个Iterator 而不是Iterable,但后者更有用,因为它可以在增强的for循环中使用。

请注意这里还有一个小问题,如果List 可以同时修改,则存在竞争条件。这发生在此处的代码中:

list.listIterator(list.size())

如果有可能,您要么必须在列表上使用外部同步,要么如果列表是CopyOnWriteArrayList,则必须先克隆它。有关后者的更多信息,请参阅this answer

【讨论】:

    【解决方案2】:

    有没有解释为什么 descendingIterator 在 List 中不存在?

    迭代列表的效率在很大程度上取决于该列表的实现。
    在设计接口时,您通常希望该接口适用于它的任何可能的实现。

    Java 链表是一个双重链表,这意味着每个元素都链接到它之前和之后的元素,因此可以编写高效的升序和降序迭代器。

    如果您使用 单个 链表,那么对它进行降序迭代将非常低效,您需要遍历整个列表直到每次迭代的当前索引。

    我怀疑正是出于这个原因,语言设计者决定从 List 接口中省略一个降序迭代器。

    使用基于索引的方法可以相当容易地实现高效的 ArrayList 降序迭代器,但在 LinkedList 上使用索引方法会比其首选实现慢得多。

    递减迭代方法的一些示例:

    for(int i=list.size() -1; i >= 0; i--){
        System.out.println(list.get(i));
    }
    
    IntStream.range(0, list.size())
            .map(i-> list.size() - 1 - i)
            .mapToObj(list::get)
            .forEach(System.out::println);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-16
      • 2012-12-28
      • 1970-01-01
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多