182 votes

Liste générique - déplacer un élément dans la liste

J'ai donc une liste générique, et une oldIndex et un newIndex valeur.

Je veux déplacer l'élément à oldIndex à newIndex ...aussi simplement que possible.

Des suggestions ?

Note

L'article doit se retrouver entre les articles à (newIndex - 1) et newIndex avant il a été supprimé.

2 votes

Vous devez modifier la réponse que vous avez cochée. Celle avec newIndex-- n'aboutit pas au comportement que vous avez dit vouloir.

2 votes

@Miral - Selon vous, quelle réponse devrait être acceptée ?

4 votes

De jpierson. Il en résulte que l'objet qui se trouvait à oldIndex avant le déplacement se retrouve à newIndex après le déplacement. C'est le comportement le moins surprenant (et c'est ce dont j'avais besoin lorsque j'écrivais un code de réorganisation par glisser-déposer). Il est vrai qu'il parle de ObservableCollection et non un générique List<T> Mais il est facile d'intervertir les appels de méthode pour obtenir le même résultat.

163voto

jpierson Points 3871

Je sais que tu as dit "liste générique", mais tu n'as pas précisé que tu devais utiliser la fonction Liste(T) alors voici une tentative de quelque chose de différent.

Le site Collection Observable(T) a un Méthode de déplacement qui fait exactement ce que vous voulez.

public void Move(int oldIndex, int newIndex)

En dessous, il y a En gros, mis en œuvre comme ça.

T item = base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, item);

Ainsi, comme vous pouvez le constater, la méthode d'échange que d'autres ont suggérée est essentiellement ce que la Collection d'Observables dans sa propre méthode Move.

MISE À JOUR 2015-12-30 : Vous pouvez voir le code source de la Déplacements et MoveItem dans corefx maintenant pour vous-même sans utiliser Reflector/ILSpy puisque .NET est open source.

37 votes

Je me demande pourquoi cela n'est pas implémenté sur la List<T> également, quelqu'un peut m'éclairer à ce sujet ?

2 votes

Quelle est la différence entre une liste générique et une classe List(T) ? Je pensais que c'était la même chose :(

1 votes

Une "liste générique" peut désigner n'importe quel type de structure de données de type liste ou collection dans .NET, y compris ObservableCollection(T) ou d'autres classes qui peuvent mettre en œuvre une structure de données de type liste. écoutez comme IList/ICollection/IEnumerable.

148voto

Garry Shutler Points 20898
var item = list[oldIndex];

list.RemoveAt(oldIndex);

if (newIndex > oldIndex) newIndex--; 
// the actual index could have shifted due to the removal

list.Insert(newIndex, item);

Mettez dans les méthodes d'extension qu'ils ressemblent :

    public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
    {
        var item = list[oldIndex];

        list.RemoveAt(oldIndex);

        if (newIndex > oldIndex) newIndex--;
        // the actual index could have shifted due to the removal

        list.Insert(newIndex, item);
    }

    public static void Move<T>(this List<T> list, T item, int newIndex)
    {
        if (item != null)
        {
            var oldIndex = list.IndexOf(item);
            if (oldIndex > -1)
            {
                list.RemoveAt(oldIndex);

                if (newIndex > oldIndex) newIndex--;
                // the actual index could have shifted due to the removal

                list.Insert(newIndex, item);
            }
        }

    }

9 votes

Votre solution s'effondre s'il y a deux copies de l'élément dans la liste, dont l'une se trouve avant oldIndex. Vous devriez utiliser RemoveAt pour être sûr de récupérer la bonne copie.

0 votes

@Garry, je suis désolé d'avoir supprimé votre commentaire sur mon autre réponse mais puisque nous ne nous soucions pas de l'emplacement de l'élément sur le newIndex avant le déplacement, dans ce cas, le déplacement est aussi bien que l'échange des éléments.

1 votes

@GarryShutler Je ne vois pas comment l'index pourrait changer si nous supprimons puis insérons un seul élément. Décrémenter l newIndex casse en fait mon test (voir ma réponse ci-dessous).

12voto

M4N Points 48758

List<T>.Remove() et List<T>.RemoveAt() ne renvoient pas l'élément qui est supprimé.

Vous devez donc l'utiliser :

var item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);

5voto

Megacan Points 1856

Insérer l'élément actuellement à oldIndex pour être à newIndex et ensuite supprimer l'instance originale.

list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);

Vous devez tenir compte du fait que l'indice de l'élément que vous voulez supprimer peut changer en raison de l'insertion.

4 votes

Vous devez enlever avant d'insérer ... votre commande peut provoquer une allocation de la liste.

-1voto

bruno conde Points 28120

Le moyen le plus simple :

list[newIndex] = list[oldIndex];
list.RemoveAt(oldIndex);

EDIT

La question n'est pas très claire... Puisque nous ne nous soucions pas de l'endroit où le list[newIndex] item goes Je pense que la façon la plus simple de procéder est la suivante (avec ou sans méthode d'extension) :

    public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
    {
        T aux = list[newIndex];
        list[newIndex] = list[oldIndex];
        list[oldIndex] = aux;
    }

Cette solution est la plus rapide car elle n'implique pas d'insertions/suppressions de listes.

5 votes

Cela va écraser l'élément à newIndex, et non l'insérer.

0 votes

@Garry Le résultat final ne sera-t-il pas le même ?

5 votes

Non, vous finirez par perdre la valeur à newIndex, ce qui ne se produirait pas si vous insériez.

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