web-dev-qa-db-fra.com

Peut-on faire une boucle pour chaque boucle en Java dans l’ordre inverse?

J'ai besoin de parcourir une liste dans l'ordre inverse en utilisant Java. 

Alors, où cela fait-il avancer:

for(String string: stringList){
//...do something
}

Est-il possible d'itérer la chaîne de caractères dans l'ordre inverse en utilisant la syntaxe pour chaque?

Pour plus de clarté: je sais comment parcourir une liste dans l’ordre inverse, mais j'aimerais savoir (par curiosité) comment le faire dans le style for each.

134
Ron Tuffin

La méthode Collections.reverse renvoie en fait une nouvelle liste avec les éléments de la liste d'origine copiés dans l'ordre inverse, si bien que O(n) est performant par rapport à la taille de la liste d'origine.

Comme solution plus efficace, vous pouvez écrire un décorateur qui présente une vue inversée d’une liste sous la forme d’une itération. L'itérateur renvoyé par votre décorateur utiliserait le ListIterator de la liste décorée pour parcourir les éléments dans l'ordre inverse.

Par exemple:

public class Reversed<T> implements Iterable<T> {
    private final List<T> original;

    public Reversed(List<T> original) {
        this.original = original;
    }

    public Iterator<T> iterator() {
        final ListIterator<T> i = original.listIterator(original.size());

        return new Iterator<T>() {
            public boolean hasNext() { return i.hasPrevious(); }
            public T next() { return i.previous(); }
            public void remove() { i.remove(); }
        };
    }

    public static <T> Reversed<T> reversed(List<T> original) {
        return new Reversed<T>(original);
    }
}

Et vous l'utiliseriez comme:

import static Reversed.reversed;

...

List<String> someStrings = getSomeStrings();
for (String s : reversed(someStrings)) {
    doSomethingWith(s);
}
147
Nat

Pour une liste, vous pouvez utiliser le Google Guava Library :

_for (String item : Lists.reverse(stringList))
{
    // ...
}
_

Notez que Lists.reverse n'inverse pas l'intégralité de la collection, ou ne fait rien qui ressemble à cela - cela permet simplement l'itération et l'accès aléatoire, dans le ordre inverse. Ceci est plus efficace que d’inverser la collection en premier.

Pour inverser une itération arbitraire, vous devez tout lire, puis "rejouer" à l'envers.

(Si vous ne l'utilisez pas déjà, je vous recommanderais vivement de jeter un coup d'œil au Guava . C'est génial.)

94
Jon Skeet

La liste (contrairement à l'ensemble) est une collection ordonnée sur laquelle itérer conserve l'ordre par contrat. Je m'attendrais à ce qu'une pile répète dans l'ordre inverse, mais malheureusement, ce n'est pas le cas. La solution la plus simple à laquelle je puisse penser est la suivante:

for (int i = stack.size() - 1; i >= 0; i--) {
    System.out.println(stack.get(i));
}

Je me rends compte que ce n'est pas une solution de boucle "pour chaque". Je préfère utiliser la boucle for que de créer une nouvelle bibliothèque telle que Google Collections.

Collections.reverse () effectue également le travail, mais il met à jour la liste au lieu de renvoyer une copie dans l'ordre inverse.

34
Gopi Reddy

Cela va déconner avec la liste originale et doit également être appelé en dehors de la boucle . Aussi, vous ne voulez pas effectuer une inversion chaque fois que vous bouclez - cela serait-il vrai si l'un des Iterables.reverse ideas était appliqué?

Collections.reverse(stringList);

for(String string: stringList){
//...do something
}
8
Phillip Gibb

Autant que je sache, la bibliothèque standard ne prend pas en charge le type standard "reverse_iterator" qui prend en charge la syntaxe for-each, qui est déjà un sucre syntaxique introduit tardivement dans le langage. 

Vous pouvez faire quelque chose comme pour (élément Item: myList.clone (). Reverse ()) et payer le prix correspondant. 

Cela semble également assez compatible avec le phénomène apparent de ne pas vous fournir de moyens pratiques d'effectuer des opérations coûteuses - puisqu'un liste, par définition, pourrait avoir une complexité d'accès aléatoire O(N) lien), l’itération inverse pourrait finir par être O (N ^ 2). Bien sûr, si vous avez une liste de tableaux, vous ne payez pas ce prix. 

4
Uri

Cela peut être une option. J'espère qu'il y a un meilleur moyen de commencer à partir du dernier élément que de boucler jusqu'à la fin.

public static void main(String[] args) {        
    List<String> a = new ArrayList<String>();
    a.add("1");a.add("2");a.add("3");a.add("4");a.add("5");

    ListIterator<String> aIter=a.listIterator();        
    while(aIter.hasNext()) aIter.next();

    for (;aIter.hasPrevious();)
    {
        String aVal = aIter.previous();
        System.out.println(aVal);           
    }
}
2
Krishna

À partir de le commentaire : Vous devriez pouvoir utiliser Apache Commons ReverseListIterator

Iterable<String> reverse 
    = new IteratorIterable(new ReverseListIterator(stringList));

for(String string: reverse ){
    //...do something
}

Comme @rogerdpack a dit , vous devez placer la ReverseListIterator comme une Iterable

2
serv-inc

Non sans avoir écrit un code personnalisé qui vous donnera un énumérateur qui inversera les éléments pour vous.

Vous devriez pouvoir le faire en Java en créant une implémentation personnalisée d'Iterable qui renverra les éléments dans l'ordre inverse.

Ensuite, vous instancieriez le wrapper (ou appelez la méthode, what-have-you) qui renverrait l'implémentation Iterable qui inverse l'élément dans la boucle.

1
casperOne

Vous pouvez utiliser la classe Collections http://Java.Sun.com/j2se/1.4.2/docs/api/Java/util/Collections.html pour inverser la liste puis la boucle.

1
Allan

Vous devez inverser votre collection si vous souhaitez utiliser la syntaxe pour chaque syntaxe prête à l'emploi et procéder dans l'ordre inverse.

1
Owen

Toutes les réponses ci-dessus ne remplissent que l'exigence, soit en encapsulant une autre méthode, soit en appelant un code étranger à l'extérieur;

Voici la solution copiée à partir de Penser en Java 4e édition , chapitre 11.13.1 AdapterMethodIdiom ;

Voici le code:

// The "Adapter Method" idiom allows you to use foreach
// with additional kinds of Iterables.
package holding;
import Java.util.*;

@SuppressWarnings("serial")
class ReversibleArrayList<T> extends ArrayList<T> {
  public ReversibleArrayList(Collection<T> c) { super(c); }
  public Iterable<T> reversed() {
    return new Iterable<T>() {
      public Iterator<T> iterator() {
        return new Iterator<T>() {
          int current = size() - 1; //why this.size() or super.size() wrong?
          public boolean hasNext() { return current > -1; }
          public T next() { return get(current--); }
          public void remove() { // Not implemented
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }
}   

public class AdapterMethodIdiom {
  public static void main(String[] args) {
    ReversibleArrayList<String> ral =
      new ReversibleArrayList<String>(
        Arrays.asList("To be or not to be".split(" ")));
    // Grabs the ordinary iterator via iterator():
    for(String s : ral)
      System.out.print(s + " ");
    System.out.println();
    // Hand it the Iterable of your choice
    for(String s : ral.reversed())
      System.out.print(s + " ");
  }
} /* Output:
To be or not to be
be to not or be To
*///:~
1
qiwen li

Certainement une réponse tardive à cette question. Une possibilité consiste à utiliser ListIterator dans une boucle for. Ce n'est pas aussi propre que la syntaxe du côlon, mais cela fonctionne.

List<String> exampleList = new ArrayList<>();
exampleList.add("One");
exampleList.add("Two");
exampleList.add("Three");

//Forward iteration
for (String currentString : exampleList) {
    System.out.println(currentString); 
}

//Reverse iteration
for (ListIterator<String> itr = exampleList.listIterator(exampleList.size()); itr.hasPrevious(); /*no-op*/ ) {
    String currentString = itr.previous();
    System.out.println(currentString); 
}

Le crédit pour la syntaxe ListIterator va à "Méthodes d'itération sur une liste en Java"

0
ScottMichaud