簡體   English   中英

在 java 中以相反順序遍歷列表

[英]Iterating through a list in reverse order in java

我正在遷移一段代碼以使用 generics。 這樣做的一個論點是,for 循環比跟蹤索引或使用顯式迭代器要干凈得多。

在大約一半的情況下,現在使用索引以相反的順序迭代列表(一個 ArrayList)。

有人可以建議一種更簡潔的方法(因為我不喜歡使用集合時的indexed for loop ),盡管它確實有效?

 for (int i = nodes.size() - 1; i >= 0; i--) {
    final Node each = (Node) nodes.get(i);
    ...
 }

注意:我不能在 JDK 之外添加任何新的依賴項。

嘗試這個:

// Substitute appropriate type.
ArrayList<...> a = new ArrayList<...>();

// Add elements to list.

// Generate an iterator. Start just after the last element.
ListIterator li = a.listIterator(a.size());

// Iterate in reverse.
while(li.hasPrevious()) {
  System.out.println(li.previous());
}

Guava提供Lists#reverse(List)ImmutableList#reverse() 在 Guava 的大多數情況下,如果參數是ImmutableList ,則前者委托給后者,因此您可以在所有情況下使用前者。 這些不會創建列表的新副本,而只是創建它的“反向視圖”。

例子

List reversed = ImmutableList.copyOf(myList).reverse();

我認為不可能使用 for 循環語法。 我唯一能建議的是做這樣的事情:

Collections.reverse(list);
for (Object o : list) {
  ...
}

...但我不會說這是“更干凈”,因為它會降低效率。

選項 1:您是否考慮過使用Collections#reverse()反轉 List,然后使用 foreach?

當然,您可能還想重構您的代碼,以便正確排序列表,這樣您就不必反轉它,這會占用額外的空間/時間。


編輯:

選項 2:或者,您可以使用Deque而不是 ArrayList 嗎? 它將允許您向前和向后迭代


編輯:

選項 3:正如其他人所建議的,您可以編寫一個迭代器來反向遍歷列表,這是一個示例:

import java.util.Iterator;
import java.util.List;

public class ReverseIterator<T> implements Iterator<T>, Iterable<T> {

    private final List<T> list;
    private int position;

    public ReverseIterator(List<T> list) {
        this.list = list;
        this.position = list.size() - 1;
    }

    @Override
    public Iterator<T> iterator() {
        return this;
    }

    @Override
    public boolean hasNext() {
        return position >= 0;
    }

    @Override
    public T next() {
        return list.get(position--);
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

}


List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");

for (String s : new ReverseIterator<String>(list)) {
    System.out.println(s);
}

您可以使用具體類LinkedList而不是通用接口List 然后你有一個descendingIterator用於反向迭代。

LinkedList<String > linkedList;
for( Iterator<String > it = linkedList.descendingIterator(); it.hasNext(); ) {
    String text = it.next();
}

不知道為什么沒有帶有ArrayList descendingIterator ArrayList ......

這是一個老問題,但它缺乏對 java8 友好的答案。 以下是在 Streaming API 的幫助下反向迭代列表的一些方法:

List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 3, 3, 7, 5));
list.stream().forEach(System.out::println); // 1 3 3 7 5

int size = list.size();

ListIterator<Integer> it = list.listIterator(size);
Stream.generate(it::previous).limit(size)
    .forEach(System.out::println); // 5 7 3 3 1

ListIterator<Integer> it2 = list.listIterator(size);
Stream.iterate(it2.previous(), i -> it2.previous()).limit(size)
    .forEach(System.out::println); // 5 7 3 3 1

// If list is RandomAccess (i.e. an ArrayList)
IntStream.range(0, size).map(i -> size - i - 1).map(list::get)
    .forEach(System.out::println); // 5 7 3 3 1

// If list is RandomAccess (i.e. an ArrayList), less efficient due to sorting
IntStream.range(0, size).boxed().sorted(Comparator.reverseOrder())
    .map(list::get).forEach(System.out::println); // 5 7 3 3 1

這是ReverseIterable的(未經測試的)實現。 iterator()被調用時,它會創建並返回一個私有的ReverseIterator實現,它只是將調用hasNext()映射到hasPrevious()並將調用next()映射到previous() 這意味着您可以按如下方式反向迭代ArrayList

ArrayList<String> l = ...
for (String s : new ReverseIterable(l)) {
  System.err.println(s);
}

類定義

public class ReverseIterable<T> implements Iterable<T> {
  private static class ReverseIterator<T> implements Iterator {
    private final ListIterator<T> it;

    public boolean hasNext() {
      return it.hasPrevious();
    }

    public T next() {
      return it.previous();
    }

    public void remove() {
      it.remove();
    }
  }

  private final ArrayList<T> l;

  public ReverseIterable(ArrayList<T> l) {
    this.l = l;
  }

  public Iterator<T> iterator() {
    return new ReverseIterator(l.listIterator(l.size()));
  }
}

如果列表相當小以至於性能不是真正的問題,則可以使用Google Guava Lists類的reverse方法。 for-each代碼的收益都很好,原始列表保持不變。 此外,反向列表由原始列表支持,因此對原始列表的任何更改都將反映在反向列表中。

import com.google.common.collect.Lists;

[...]

final List<String> myList = Lists.newArrayList("one", "two", "three");
final List<String> myReverseList = Lists.reverse(myList);

System.out.println(myList);
System.out.println(myReverseList);

myList.add("four");

System.out.println(myList);
System.out.println(myReverseList);

產生以下結果:

[one, two, three]
[three, two, one]
[one, two, three, four]
[four, three, two, one]

這意味着 myList 的反向迭代可以寫成:

for (final String someString : Lists.reverse(myList)) {
    //do something
}

非常簡單的例子:

List<String> list = new ArrayList<String>();

list.add("ravi");

list.add("kant");

list.add("soni");

// Iterate to disply : result will be as ---     ravi kant soni

for (String name : list) {
  ...
}

//Now call this method

Collections.reverse(list);

// iterate and print index wise : result will be as ---     soni kant ravi

for (String name : list) {
  ...
}

創建一個自定義reverseIterable

擁有如下所示的代碼:

List<Item> items;
...
for (Item item : In.reverse(items))
{
    ...
}

將此代碼放入名為“In.java”的文件中:

import java.util.*;

public enum In {;
    public static final <T> Iterable<T> reverse(final List<T> list) {
        return new ListReverseIterable<T>(list);
    }

    class ListReverseIterable<T> implements Iterable<T> {
        private final List<T> mList;

        public ListReverseIterable(final List<T> list) {
            mList = list;
        }

        public Iterator<T> iterator() {
            return new Iterator<T>() {
                final ListIterator<T> it = mList.listIterator(mList.size());

                public boolean hasNext() {
                    return it.hasPrevious();
                }
                public T next() {
                    return it.previous();
                }
                public void remove() {
                    it.remove();
                }
            };
        }
    }
}

還找到了 google collections reverse方法。

正如至少兩次建議的那樣,您可以將descendingIteratorDeque一起使用,尤其是與LinkedList一起使用。 如果你想使用 for-each 循環(即有一個Iterable ),你可以構造和使用這樣的包裝器:

import java.util.*;

public class Main {

    public static class ReverseIterating<T> implements Iterable<T> {
        private final LinkedList<T> list;

        public ReverseIterating(LinkedList<T> list) {
            this.list = list;
        }

        @Override
        public Iterator<T> iterator() {
            return list.descendingIterator();
        }
    }

    public static void main(String... args) {
        LinkedList<String> list = new LinkedList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");

        for (String s : new ReverseIterating<String>(list)) {
            System.out.println(s);
        }
    }
}
Valid for Java 9+

List<String> strList = List.of("a", "b", "c", "d", "e");

IntStream.iterate(strList.size() - 1, i -> i >= 0, i -> --i)
         .mapToObj(strList::get)
         .forEach(System.out::println);

德奎呢? IE

      var queue = new ArrayDeque<>(list);
      while (!queue.isEmpty()) {
        var first = reversed ? queue.removeLast() : queue.removeFirst();
        var second = reversed ? queue.peekLast() : queue.peekFirst();
        if (second != null) {
          //your code goes here
        }
      }

原因:“不知道為什么沒有帶有ArrayList的descendingIterator...”

由於數組列表不會以與添加到列表中的數據相同的順序保存列表。 所以,永遠不要使用 Arraylist 。

鏈表將按照 ADD 到列表的相同順序保存數據。

所以,在我上面的例子中,我使用了 ArrayList() 來讓用戶扭曲他們的想法,讓他們從他們身邊鍛煉一些東西。

而不是這個

List<String> list = new ArrayList<String>();

用:

List<String> list = new LinkedList<String>();

list.add("ravi");

list.add("kant");

list.add("soni");

// Iterate to disply : result will be as ---     ravi kant soni

for (String name : list) {
  ...
}

//Now call this method

Collections.reverse(list);

// iterate and print index wise : result will be as ---     soni kant ravi

for (String name : list) {
  ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM