Je migre un morceau de code pour utiliser des génériques. Un argument en ce sens est que la boucle for est beaucoup plus propre que le suivi des index ou l'utilisation d'un itérateur explicite.
Dans environ la moitié des cas, la liste (un ArrayList) est itérée dans l'ordre inverse en utilisant un index aujourd'hui.
Quelqu'un peut-il suggérer une méthode plus propre pour le faire (puisque je n'aime pas le indexed for loop
lorsque je travaille avec des collections), bien que cela fonctionne?
for (int i = nodes.size() - 1; i >= 0; i--) {
final Node each = (Node) nodes.get(i);
...
}
Note: Je ne peux ajouter aucune nouvelle dépendance en dehors du JDK.
Essaye ça:
// 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 offre Lists#reverse(List)
et ImmutableList#reverse()
. Comme dans la plupart des cas pour Guava, le premier délègue à ce dernier si l'argument est un ImmutableList
, vous pouvez donc utiliser le premier dans tous les cas. Ceux-ci ne créent pas de nouvelles copies de la liste mais juste des "vues inversées" de celle-ci.
Exemple
List reversed = ImmutableList.copyOf(myList).reverse();
Je ne pense pas qu'il soit possible d'utiliser la syntaxe de la boucle for. La seule chose que je peux suggérer est de faire quelque chose comme:
Collections.reverse(list);
for (Object o : list) {
...
}
... mais je ne dirais pas que c'est "plus propre" étant donné que ça va être moins efficace.
Option 1: Avez-vous pensé à inverser la liste avec Collections # reverse () et à utiliser ensuite foreach?
Bien sûr, vous pouvez également vouloir refactoriser votre code de telle sorte que la liste soit ordonnée correctement, de sorte que vous n'ayez pas à l'inverser, qui utilise un espace/temps supplémentaire.
MODIFIER:
Option 2: Sinon, pourriez-vous utiliser un Deque au lieu d'un ArrayList? Cela vous permettra d'itérer en avant et en arrière
MODIFIER:
Option 3: comme d'autres l'ont suggéré, vous pouvez écrire un Iterator qui parcourt la liste à l'envers, voici un exemple:
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);
}
Vous pouvez utiliser la classe concrète LinkedList
au lieu de l'interface générale List
. Ensuite, vous avez un descendingIterator
pour effectuer une itération en sens inverse.
LinkedList<String > linkedList;
for( Iterator<String > it = linkedList.descendingIterator(); it.hasNext(); ) {
String text = it.next();
}
Je ne sais pas pourquoi il n'y a pas descendingIterator
avec ArrayList
...
C'est une vieille question, mais il manque une réponse compatible Java8. Voici quelques façons de procéder à une itération inverse de la liste, à l'aide de l'API Streaming:
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
Créez une reverseIterable
personnalisée.
Si les listes sont assez petites pour que les performances ne soient pas un réel problème, on peut utiliser la méthode reverse
- de la classe Lists
de Google Guava
. Rend joli for-each
- code, et la liste originale reste la même. De plus, la liste inversée est accompagnée de la liste d'origine. Toute modification apportée à la liste d'origine sera donc reflétée dans la liste inversée.
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);
Donne le résultat suivant:
[one, two, three]
[three, two, one]
[one, two, three, four]
[four, three, two, one]
Ce qui signifie que l'itération inverse de myList peut être écrite comme suit:
for (final String someString : Lists.reverse(myList)) {
//do something
}
Voici une implémentation (non testée) d'un ReverseIterable
. Lorsque iterator()
est appelé, il crée et retourne une implémentation privée ReverseIterator
, qui mappe simplement les appels à hasNext()
à hasPrevious()
et les appels à next()
sont mappés à previous()
. Cela signifie que vous pouvez itérer sur un ArrayList
en sens inverse:
ArrayList<String> l = ...
for (String s : new ReverseIterable(l)) {
System.err.println(s);
}
Définition de classe
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()));
}
}
Exemple très simple:
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) {
...
}
Vous pouvez utiliser ReverseListIterator
de Apache Commons-Collections:
Aussi trouvé google collections inverse méthode.
Pour avoir un code qui ressemble à ceci:
List<Item> items;
...
for (Item item : In.reverse(items))
{
...
}
Placez ce code dans un fichier appelé "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();
}
};
}
}
}
Comme cela a été suggéré au moins deux fois, vous pouvez utiliser descendingIterator
avec un Deque
, en particulier avec un LinkedList
. Si vous souhaitez utiliser la boucle for-each (c'est-à-dire avoir un Iterable
), vous pouvez construire et utiliser un wraper comme celui-ci:
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);
}
}
}