Итерация по списку в обратном порядке в java [дубликат]



этот вопрос уже есть ответ здесь:



я переношу часть кода, чтобы использовать дженерики. Одним из аргументов для этого является то, что цикл for намного чище, чем отслеживание индексов или использование явного итератор.



примерно в половине случаев список (ArrayList) повторяется в обратном порядке с помощью индекса сегодня.



может кто-то предложить более чистый способ сделать это (так как мне не нравится indexed for loop при работе с коллекциями), хотя он работает?



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


Примечание: я не могу добавить никаких новых зависимостей за пределами JDK.

496   15  

15 ответов:

попробуйте это:

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

Я не думаю, что это возможно с помощью синтаксиса цикла. Единственное, что я могу предложить-это сделать что-то вроде:

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

... но я бы не сказал, что это "чище", учитывая, что это будет менее эффективным.

Вариант 1: вы думали о реверсировании списка с помощью коллекции#reverse () и затем с помощью foreach?

конечно, вы также можете выполнить рефакторинг кода, таких, что список правильно упорядочены таким образом, вы не должны обратить его, который использует дополнительное пространство/время.


EDIT:

Вариант 2: в качестве альтернативы, не могли бы вы использовать Deque вместо ArrayList? Это позволит вам перебирать вперед и назад


EDIT:

Вариант 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();
}

не знаю, почему нет descendingIterator С ArrayList...

если списки довольно малы, так что производительность не является реальной проблемой, можно использовать reverse-метод Lists-класс Google Guava. Урожайность довольно 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
}

создать пользовательское reverseIterable.

Это старый вопрос, но ему не хватает 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

вот (непроверенная) реализация a ReverseIterable. Когда iterator() называется он создает и возвращает private 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()));
  }
}

простой пример:

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) {
  ...
}

также нашел в коллекциях компании Google реверс метод.

вы могли бы использовать ReverseListIterator из Apache Commons-Collections:

https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/iterators/ReverseListIterator.html

есть код, который выглядит так:

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

как было предложено по крайней мере дважды, вы можете использовать descendingIterator С Deque, в частности LinkedList. Если вы хотите использовать цикл for-each (т. е. иметь Iterable), вы можете построить и использовать wraper такой:

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

причина: "не знаю, почему нет никакого descendingIterator с ArrayList..."

поскольку список массивов не сохраняет список в том же порядке, что и данные, добавленные в список. Поэтому никогда не используйте Arraylist .

связанный список будет хранить данные в том же порядке добавления в список.

Итак, выше в моем примере я использовал 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) {
  ...
}

Comments

    Ничего не найдено.