Peut-on faire pour chaque boucle en java dans l'ordre inverse?

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

ainsi, où cela fait-il suivre:

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

y a-t-il un moyen d'itérer la chaîne de caractères dans l'ordre inverse en utilisant le pour chaque syntaxe ?

pour plus de clarté: je sais comment itérer une liste dans l'ordre inverse mais je voudrais savoir (pour le bien de curiosity ) comment le faire dans le pour chaque style .

133
demandé sur Ron Tuffin 2009-07-08 17:34:07

12 réponses

N'utilisez pas les Collections.méthode inverse il inverse en fait la liste originale en place. Si vous l'utilisez:

mauvaise direction!

Collections.reverse(new ArrayList(stringList))

pour éviter de modifier l'original, ceci renvoie une nouvelle liste avec les éléments de la liste originale copiés dans l'ordre inverse, et cela a O(n) les performances et les exigences d'espace en ce qui concerne la taille de la liste originale.

comme un plus solution efficace, vous pouvez écrire une classe qui présente une vue inversée d'une liste en tant que Générique itérable. L'itérateur retourné par votre classe utiliserait le ListIterator de la liste décorée pour marcher sur 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'utilisez comme:

import static Reversed.reversed;

...

List<String> someStrings = getSomeStrings();
for (String s : reversed(someStrings)) {
    doSomethingWith(s);
}
139
répondu Nat 2016-03-07 18:15:13

pour une liste, vous pouvez utiliser le Bibliothèque Google Guava :

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

noter que Lists.reverse ne pas inverser la collection entière, ou faire quelque chose comme elle - il permet juste l'itération et l'accès aléatoire, dans l'ordre inverse. C'est plus efficace que d'inverser la collecte d'abord.

pour inverser une itérabilité arbitraire, il faut tout lire et puis "replay" à l'envers.

(si vous ne l'utilisez pas déjà, je minutieusement vous recommande d'avoir un oeil au Goyave . C'est un truc très.)

88
répondu Jon Skeet 2016-06-29 07:59:11

la liste (contrairement à L'ensemble) est une collection ordonnée et itérer sur elle ne préserve l'ordre par contrat. Je m'attendais à ce qu'une pile se répète dans l'ordre inverse, mais malheureusement ce n'est pas le cas. Donc la solution la plus simple à laquelle je peux penser est celle-ci:

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

je me rends compte qu'il ne s'agit pas d'une solution" pour chaque " boucle. Je préfère utiliser la boucle for plutôt que d'introduire une nouvelle bibliothèque comme les collections Google.

Collections.inverser() aussi fait le travail, mais il met à jour la liste plutôt que de retourner une copie dans l'ordre inverse.

32
répondu Gopi Reddy 2011-05-20 16:01:53

cela va interférer avec la liste originale et doit aussi être appelé en dehors de la boucle. En outre, vous ne voulez pas effectuer une inversion chaque fois que vous bouclez-serait-ce vrai si l'un des Iterables.reverse ideas a été appliquée?

Collections.reverse(stringList);

for(String string: stringList){
//...do something
}
8
répondu Phillip Gibb 2011-11-21 16:49:18

AFAIK il n'y a pas une sorte de "réverse_iterator" standard dans la bibliothèque standard qui supporte la syntaxe pour-chaque qui est déjà un sucre syntaxique qu'ils ont apporté tard dans la langue.

Vous pourriez faire quelque chose comme(Élément de l'élément: maliste.clone.)(reverse()) et de payer le prix associé.

cela semble également assez cohérent avec le phénomène apparent de ne pas vous donner des moyens pratiques pour faire des opérations coûteuses-depuis une list, par définition, pourrait avoir O (N) la complexité d'accès aléatoire(vous pourriez implémenter l'interface avec un simple lien), l'itération inverse pourrait finir par être O (N^2). Bien sûr, si vous avez un ArrayList, vous ne payez pas ce prix.

4
répondu Uri 2009-07-08 13:55:42

ceci peut être une option. J'espère qu'il y a une meilleure façon de commencer à partir du dernier élément que de boucler la boucle 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
répondu Krishna 2012-03-01 12:55:02

à 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 envelopper le ReverseListIterator comme un Iterable .

2
répondu serv-inc 2017-05-23 11:55:07

pas sans écrire un code personnalisé qui vous donnera un recenseur qui inversera les éléments pour vous.

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

ensuite, vous instanciez le wrapper (ou appelez la méthode, what-have-you) qui retournerait l'implémentation itérative qui inverse l'élément dans la boucle pour chaque boucle.

1
répondu casperOne 2009-07-08 13:37:57

vous pouvez utiliser la classe de Collections http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html pour inverser la liste puis boucle.

1
répondu Allan 2009-07-08 13:38:38

Vous deviez annuler votre collection si vous souhaitez utiliser la syntaxe pour tout hors de la boîte et aller dans l'ordre inverse.

1
répondu Owen 2009-07-08 13:39:13

toutes les réponses ci-dessus remplissent seulement l'exigence, soit en enveloppant une autre méthode ou en appelant un code étranger à l'extérieur;

Voici la solution copiée du penser en Java 4ème édition , chapitre 11.13.1 Adaptermethodiom ;

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
répondu qiwen li 2017-03-14 11:15:34

certainement une réponse tardive à cette question. Une possibilité est d'utiliser le ListIterator dans une boucle for. Ce n'est pas aussi propre que la syntaxe du côlon, mais ça marche.

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 à "façons d'itérer sur une liste en Java"

0
répondu ScottMichaud 2018-09-01 22:08:15