Comment obtenir une vue de liste inversée sur une liste en Java?


214

Je veux avoir une vue de liste inversée sur une liste (d'une manière similaire à celle qui List#sublistfournit une vue de sous-liste sur une liste). Y a-t-il une fonction qui fournit cette fonctionnalité?

Je ne veux pas faire de copie de la liste ni modifier la liste.

Ce serait suffisant si je pouvais obtenir au moins un itérateur inversé sur une liste dans ce cas.


De plus, je sais comment l'implémenter moi-même. Je demande simplement si Java fournit déjà quelque chose comme ça.

Mise en œuvre de la démonstration:

static <T> Iterable<T> iterableReverseList(final List<T> l) {
    return new Iterable<T>() {
        public Iterator<T> iterator() {
            return new Iterator<T>() {
                ListIterator<T> listIter = l.listIterator(l.size());                    
                public boolean hasNext() { return listIter.hasPrevious(); }
                public T next() { return listIter.previous(); }
                public void remove() { listIter.remove(); }                 
            };
        }
    };
}

Je viens de découvrir que certaines Listimplémentations ont descendingIterator()ce dont j'ai besoin. Bien qu'il n'y ait pas une telle mise en œuvre générale pour List. Ce qui est LinkedListassez étrange car l'implémentation que j'ai vue dans est assez générale pour fonctionner avec n'importe laquelle List.


1
Pouvez-vous construire la liste dans l'ordre inverse pour commencer?
Tony Ennis

Oui, c'est le cas - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer

Si vous visitez ce lien pour trouver la réponse comment inverser (modifier) ​​la liste, Collections.reverse(list)
voici

Réponses:


210

La goyave fournit ceci: Lists.reverse (List)

List<String> letters = ImmutableList.of("a", "b", "c");
List<String> reverseView = Lists.reverse(letters); 
System.out.println(reverseView); // [c, b, a]

Contrairement à Collections.reverse, c'est purement une vue ... cela ne modifie pas l'ordre des éléments dans la liste d'origine. En outre, avec une liste d'origine modifiable, les modifications apportées à la fois à la liste d'origine et à la vue sont répercutées dans l'autre.


11
Le problème est que Guava est une très grande bibliothèque. Voir la discussion: github.com/google/guava/issues/1954 et code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito: ProGuard est toujours la meilleure solution pour la taille de la bibliothèque, bien que nous puissions apporter des améliorations. En tout cas, je ne pense pas que la taille de la bibliothèque soit pertinente de quelque façon que ce soit à cette réponse.
ColinD

2
Oui, la taille de la bibliothèque n'est pas pertinente pour cette réponse, mais est pertinente pour être informée pour les programmeurs (donc, j'ai commenté)! Merci beaucoup pour cette excellente bibliothèque et pour votre suggestion @ColinD!
Filipe Brito

@ColinD, yup, c'était mon erreur. Un collègue a ajouté google-collections qui ont également le même espace de noms et class ( List) mais sans méthode inverse. le retirer a rendu la goyave à nouveau disponible.
AaA

Les développeurs n'ont pas toujours le contrôle sur les bibliothèques qu'ils peuvent utiliser, et l'ajout d'une toute nouvelle bibliothèque pour quelque chose d'aussi simple semble exagéré - d'autant plus que le problème peut être résolu avecListIterator.previous()
Jonathan Benn

218

Utilisez la méthode .clone () sur votre liste. Il renverra une copie superficielle, ce qui signifie qu'il contiendra des pointeurs vers les mêmes objets, vous n'aurez donc pas à copier la liste. Ensuite, utilisez simplement Collections.

Ergo,

Collections.reverse(list.clone());

Si vous utilisez un Listet que vous n'y avez pas accès, clone()vous pouvez utiliser subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);

21
clone()créerait normalement une copie de la liste. Quoi qu'il en soit, List#clone()n'existe pas non plus.
Albert

6
Vous avez techniquement raison, l'interface List elle-même ne fournit pas la méthode clone (). Mais ArrayList, LinkedList et Vector le font tous.
jcalvert

2
Je viens de regarder la mise en œuvre de clone(). Il fait en effet une copie complète de la liste (il ne clone pas seulement chaque objet de la liste mais ce n'est jamais ce dont je parlais).
Albert

21
Notez que Collections.reverse renvoie void, vous perdrez donc la référence de clone. Vous devez d'abord affecter le clone à une variable, puis le trier.
user12722

10
subListne copie pas, il fournit simplement une vue sur la liste sous-jacente, donc inverser cette vue inversera la liste sous-jacente.
Roland

80

Si j'ai bien compris, c'est une ligne de code. Cela a fonctionné pour moi.

 Collections.reverse(yourList);

12
Ce n'est pas une vue de liste. Cela modifie la liste.
Albert

35

Ce n'est pas exactement élégant, mais si vous utilisez List.listIterator (int index), vous pouvez obtenir un ListIterator bidirectionnel à la fin de la liste:

//Assume List<String> foo;
ListIterator li = foo.listIterator(foo.size());

while (li.hasPrevious()) {
   String curr = li.previous()
}

1
C'est la meilleure réponse, car (1) elle ne nécessite pas de bibliothèque et (2) elle ne modifie pas la liste d'origine, comme l'OP l'a demandé
Jonathan Benn

12

Collections.reverse (nums) ... Il inverse en fait l'ordre des éléments. Le code ci-dessous devrait être très apprécié -

List<Integer> nums = new ArrayList<Integer>();
nums.add(61);
nums.add(42);
nums.add(83);
nums.add(94);
nums.add(15);
//Tosort the collections uncomment the below line
//Collections.sort(nums); 

Collections.reverse(nums);

System.out.println(nums);

Sortie: 15,94,83,42,61


8
Vous répétez juste la réponse que quelqu'un d'autre a écrite il y a 6 ans
Jonathan Benn

1
... et non une vue. cela mute la liste.
Jason S

6

java.util.Dequea descendingIterator()- si votre Listest un Deque, vous pouvez l'utiliser.


Si vous ne vouliez pas utiliser la méthode intégrée descndingIterator (), il semble que l'utilisation d'un ConcurrentLinkedDeque serait la meilleure pour inverser une très grande liste? Fondamentalement, il suffit de copier d'un pont vers le nouveau pont en utilisant le sondage, puis d'offrir? Sorta comme avoir juste un jeu de cartes et en retirer chacun du dessus dans une nouvelle pile, dans l'ordre.
djangofan

4

Je sais que c'est un vieux post mais aujourd'hui je cherchais quelque chose comme ça. Finalement, j'ai écrit le code moi-même:

private List reverseList(List myList) {
    List invertedList = new ArrayList();
    for (int i = myList.size() - 1; i >= 0; i--) {
        invertedList.add(myList.get(i));
    }
    return invertedList;
}

Non recommandé pour les longues listes, ce n'est pas du tout optimisé. C'est une sorte de solution facile pour les scénarios contrôlés (les listes que je gère ne contiennent pas plus de 100 éléments).

J'espère que ça aide quelqu'un.


2
Votre code a un seul problème - vous pouvez y mettre n'importe quelle liste, mais il vous renverra toujours ArrayList (en tant que liste). Et si j'ai besoin de LinkedList? Il est préférable de modifier myList et de retourner void.
Dmitry Zaytsev

2
Notez que ce n'est pas vraiment ce que je demandais. Je demandais une sorte de proxy / vue, pas une copie.
Albert

4

J'utilise ceci:

public class ReversedView<E> extends AbstractList<E>{

    public static <E> List<E> of(List<E> list) {
        return new ReversedView<>(list);
    }

    private final List<E> backingList;

    private ReversedView(List<E> backingList){
        this.backingList = backingList;
    }

    @Override
    public E get(int i) {
        return backingList.get(backingList.size()-i-1);
    }

    @Override
    public int size() {
        return backingList.size();
    }

}

comme ça:

ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list

1

Vous pouvez également le faire:

static ArrayList<String> reverseReturn(ArrayList<String> alist)
{
   if(alist==null || alist.isEmpty())
   { 
       return null;
   }

   ArrayList<String> rlist = new ArrayList<>(alist);

   Collections.reverse(rlist);
   return rlist;
}

5
Ce n'est pas une vue de liste. Une vue est l'opposé d'une copie.
Albert

La liste inversée d'une liste vide est nulle ??
ShellFish

1

Vous pouvez également inverser la position lorsque vous demandez un objet:

Object obj = list.get(list.size() - 1 - position);

1

Pour une liste de petite taille, nous pouvons créer LinkedListet ensuite utiliser l'itérateur descendant comme:

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three"));
stringList.stream().collect(Collectors.toCollection(LinkedList::new))
         .descendingIterator().
         forEachRemaining(System.out::println); // Three, Two, One
System.out.println(stringList); // One, Two, Three

-3

Utilisez des reverse(...)méthodes de java.util.Collectionsclasse. Passez votre liste en paramètre et votre liste sera inversée.

Collections.reverse(list);

1
Copie d'une réponse existante
Karl Richter
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.