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.

Albert
la source
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.

ColinD
la source
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);
jcalvert
la source
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);
Shakeeb Ayaz
la source
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()
}
kkress
la source
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

Krishna Kumar Chourasiya
la source
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.

Bozho
la source
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.

CocheLee
la source
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
Museful
la source
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;
}
jhdrosos
la source
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);
fede1608
la source
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
akhil_mittal
la source
-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);
Shubho Ghosh
la source
1
Copie d'une réponse existante
Karl Richter