[java] Java에서 목록을 역순으로 반복

제네릭을 사용하기 위해 코드 조각을 마이그레이션하고 있습니다. 그렇게하는 한 가지 주장은 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());
}


답변

구아바 제공 Lists#reverse(List)하고 ImmutableList#reverse(). 구아바의 대부분의 경우와 마찬가지로, 인수가이면 전자가 후자를 위임 ImmutableList하므로 모든 경우에 전자를 사용할 수 있습니다. 이들은리스트의 새로운 사본을 생성하지 않고 단지 “역전 된 뷰”를 생성합니다.

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


답변

for 루프 구문을 사용하는 것이 가능하다고 생각하지 않습니다. 내가 제안 할 수있는 유일한 것은 다음과 같은 일을하는 것입니다.

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

…하지만 효율성이 떨어질 것이므로 이것이 더 깨끗하다고는 말할 수 없습니다.


답변

옵션 1 : Collections # reverse ()를 사용 하여 목록을 뒤집는 것에 대해 생각해 보셨습니까? foreach를 사용 ?

물론 목록을 올바르게 정렬하도록 코드를 리팩터링하여 역 / 시간을 추가로 사용하지 않아도되도록 할 수 있습니다.


편집하다:

옵션 2 : 또는 ArrayList 대신 Deque 를 사용할 수 있습니까? 앞뒤로 반복 할 수 있습니다.


편집하다:

옵션 3 : 다른 사람들이 제안했듯이 목록을 거꾸로 반복하는 Iterator를 작성할 수 있습니다. 예는 다음과 같습니다.

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

어떤이 이유를 알고하지 마십시오 descendingIteratorArrayList


답변

이것은 오래된 질문이지만 java8 친화적 인 답변이 부족합니다. 다음은 스트리밍 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()));
  }
}