Итерация по списку в обратном порядке в java
Я переношу часть кода, чтобы использовать дженерики. Один аргумент для этого состоит в том, что цикл for намного чище, чем отслеживание индексов или использование явного итератора.
Примерно в половине случаев список (ArrayList) выполняется в обратном порядке с использованием индекса сегодня.
Может ли кто-нибудь предложить более чистый способ сделать это (поскольку мне не нравится indexed for loop
при работе с коллекциями), хотя он работает?
for (int i = nodes.size() - 1; i >= 0; i--) {
final Node each = (Node) nodes.get(i);
...
}
Примечание. Я не могу добавить никаких новых зависимостей вне JDK.
Ответы
Ответ 1
Попробуйте следующее:
// 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());
}
Ответ 2
Гуава предлагает Lists#reverse(List)
и ImmutableList#reverse()
. Как и в большинстве случаев для Гуавы, первый делегирует второму, если аргумент является ImmutableList
, так что вы можете использовать первый во всех случаях. Они не создают новые копии списка, а просто "обращают взгляды" на него.
пример
List reversed = ImmutableList.copyOf(myList).reverse();
Ответ 3
Я не думаю, что это возможно с использованием синтаксиса for for. Единственное, что я могу предложить, это сделать что-то вроде:
Collections.reverse(list);
for (Object o : list) {
...
}
... но я бы не сказал, что это "чище", учитывая, что он будет менее эффективным.
Ответ 4
Вариант 1: подумали ли вы о том, чтобы перевернуть список с помощью Collections # 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);
}
Ответ 5
Вы можете использовать конкретный класс LinkedList
вместо общего интерфейса List
. Затем у вас есть descendingIterator
для повторения в обратном направлении.
LinkedList<String > linkedList;
for( Iterator<String > it = linkedList.descendingIterator(); it.hasNext(); ) {
String text = it.next();
}
Не знаю, почему нет descendingIterator
с ArrayList
...
Ответ 6
Это старый вопрос, но ему не хватает 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
Ответ 7
Создайте пользовательский reverseIterable
.
Ответ 8
Если списки довольно малы, поэтому производительность не является реальной проблемой, можно использовать reverse
-metod класса 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
}
Ответ 9
Вот (непроверенная) реализация 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()));
}
}
Ответ 10
Очень простой пример:
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) {
...
}
Ответ 11
Вы можете использовать ReverseListIterator
из Apache Commons-Collections:
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/ReverseListIterator.html
Ответ 12
Также найдены коллекции google reverse.
Ответ 13
Чтобы иметь код, который выглядит так:
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();
}
};
}
}
}
Ответ 14
Как было предложено, по крайней мере, дважды, вы можете использовать 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);
}
}
}
Ответ 15
Причина: "Не знаю, почему нет descendingIterator с ArrayList..."
Так как список массивов не сохраняет список в том же порядке, что и данные, добавленные в список. Поэтому никогда не используйте 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) {
...
}