80 votes

Déplacer des éléments dans une ArrayList

J'ai joué avec ArrayList s. Ce que j'essaie d'obtenir, c'est une méthode pour faire quelque chose comme ça :

Item 1
Item 2
Item 3
Item 4

J'essaie de pouvoir déplacer des éléments vers le haut de la liste, à moins qu'ils ne soient déjà en haut, auquel cas ils restent inchangés. Par exemple, si l'élément 3 était déplacé, la liste serait la suivante :

Item 1
Item 3
Item 2
Item 4

D'après ce que j'ai compris pour l'instant, je voudrais quelque chose de l'ordre de ce qui suit :

IF arrayname index is not equal to 0
THEN move up
ELSE do nothing

La partie qui me pose problème est celle qui concerne le "déplacement vers le haut". Tout conseil ou exemple de code sur la façon dont cela pourrait être réalisé serait très apprécié.

135voto

Mikkel Points 919

Je suis tombé sur cette vieille question en cherchant une réponse, et j'ai pensé poster la solution que j'ai trouvée au cas où quelqu'un d'autre passerait par ici en cherchant la même chose.

Pour échanger 2 éléments, Collections.swap est très bien. Mais si nous voulons déplacer plus d'éléments, il existe une meilleure solution qui implique une utilisation créative de Collections.sublist et Collections.rotate à laquelle je n'avais pas pensé avant de la voir décrite ici :

http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#rotate%28java.util.List,%20int%29

Voici une citation, mais allez-y et lisez l'intégralité du texte pour vous-même :

Notez que cette méthode peut être utilement appliquée aux sous-listes pour déplacer un ou plusieurs éléments au sein d'une liste tout en prévenant le déplacement. ou plusieurs éléments d'une liste tout en préservant l'ordre des éléments restants. éléments restants. Par exemple, l'idiome suivant déplace l'élément à l'indice j vers la position k (qui doit être supérieure ou égale à j). à j) :

Collections.rotate(list.subList(j, k+1), -1);

3 votes

Dans mon application, cette rotation de sous-liste semblait être plus lente que l'approche remove/insert décrite ici : stackoverflow.com/a/4938696/1025391

2 votes

greater than or equal (>=) ? et à propos de <= ?

0 votes

@moooeeeep il m'a fallu un certain temps pour comprendre ce que fait l'int dans rotate(list, int). Il se comporte comme un carrousel, où le dernier index passe en premier, et l'ancien -2ème au dernier index- est maintenant le dernier (lorsque des int positifs sont utilisés) ; alors que pour les négatifs, la direction change. C'est peut-être la raison pour laquelle il est plus lent parce qu'il échange chaque indice un par un( ?). à en juger par cette quête. ( stackoverflow.com/q/50212335/11214643 ), il semble que sa vitesse puisse être améliorée, mais peut-être pas pour la raison que je pointe ici. Mais sur le lien, op mentionne "Block-Swap Algorithm" serait plus rapide, ce qui donne un indice.

71voto

StriplingWarrior Points 56276

Un simple échange est bien meilleur pour "déplacer quelque chose vers le haut" dans une ArrayList :

if(i > 0) {
    Item toMove = arrayList.get(i);
    arrayList.set(i, arrayList.get(i-1));
    arrayList.set(i-1, toMove);
}

Étant donné qu'une liste matricielle utilise un tableau, si vous retirez un élément d'une liste matricielle, celle-ci doit "décaler" vers le haut tous les éléments situés après cet élément pour combler le vide dans le tableau. Si vous insérez un élément, il doit déplacer tous les éléments après cet élément pour faire de la place pour l'insérer. Ces décalages peuvent être très coûteux si votre tableau est très grand. Puisque vous savez que vous voulez finir avec le même nombre d'éléments dans la liste, faire un swap comme celui-ci vous permet de "déplacer" un élément vers un autre emplacement dans la liste de manière très efficace.

Comme le soulignent Chris Buckler et Michal Kreuzman, il existe même une méthode pratique dans la classe Collections pour réduire ces trois lignes de code à une seule :

Collections.swap(arrayList, i, i-1);

0 votes

C'est génial, les collections.swap semblent être parfaites. Un petit problème que j'ai remarqué est que l'utilisation de ce quelque chose en haut de la liste provoque une exception hors limites - cela fonctionne toujours comme je le voulais mais y a-t-il un moyen d'empêcher qu'il lance une exception hors limites ?

1 votes

@user319940 Hi StriplingWarrior l'a montré dans le premier exemple de code. L'index doit être supérieur à 0 if(i > 0)

0 votes

Heh, je suis bête, j'ai essayé avec while au lieu de if - merci encore à tous. J'espère que ce post aidera aussi d'autres personnes à l'avenir.

31voto

michal.kreuzman Points 3214

Vous pouvez essayer ce code simple, Collections.swap(list, i, j) est ce que vous recherchez.

    List<String> list = new ArrayList<String>();
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");

    String toMoveUp = "3";
    while (list.indexOf(toMoveUp) != 0) {
        int i = list.indexOf(toMoveUp);
        Collections.swap(list, i, i - 1);
    }

    System.out.println(list);

28voto

amol Points 4305

Pour monter, il faut enlever puis ajouter.

Pour enlever - ArrayList.remove et assigne l'objet retourné à une variable
Ensuite, ajoutez cet objet à l'indice requis - ArrayList.add(int index, E element)

[http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(int](http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(int) , E)

2 votes

Il s'agit de la seule solution qui fonctionne réellement pour modifier l'ordre des éléments dans la liste-réseau. Merci !

2 votes

Très élégant en effet !

1 votes

Avec la suppression, il ne s'agit pas d'un déplacement, mais d'un changement de position de deux objets (échange), tandis que le déplacement consiste à déplacer un objet entre deux autres objets.

13voto

marwils Points 354

Comme Mikkel l'a posté avant Collections.rotate est une méthode simple. J'utilise cette méthode pour déplacer des éléments vers le haut et vers le bas dans une liste.

public static <T> void moveItem(int sourceIndex, int targetIndex, List<T> list) {
    if (sourceIndex <= targetIndex) {
        Collections.rotate(list.subList(sourceIndex, targetIndex + 1), -1);
    } else {
        Collections.rotate(list.subList(targetIndex, sourceIndex + 1), 1);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X