J'ai donc une liste générique et une valeur oldIndex
et une valeur newIndex
.
Je souhaite déplacer l'élément de oldIndex
vers newIndex
... aussi simplement que possible.
Aucune suggestion?
L'élément doit être fini entre les éléments à (newIndex - 1)
et newIndex
avant il a été supprimé.
Je sais que vous avez dit "liste générique" mais vous n'avez pas précisé que vous deviez utiliser la classe List (T), voici donc un aperçu de quelque chose de différent.
La classe ObservableCollection (T) a une méthode de déplacement qui fait exactement ce que vous voulez.
public void Move(int oldIndex, int newIndex)
En dessous, il est en gros implémenté comme ceci.
T item = base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, item);
Comme vous pouvez le constater, la méthode de swap suggérée par d’autres personnes correspond essentiellement à ce que ObservableCollection utilise dans sa propre méthode de déplacement.
UPDATE 2015-12-30: Vous pouvez voir le code source de Move et MoveItem méthodes dans corefx maintenant pour vous-même sans utiliser Reflector/ILSpy puisque .NET est open source.
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);
Je sais que cette question est ancienne mais je me suis adapté THIS réponse du code javascript à C #. J'espère que ça aide
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
// exit if possitions are equal or outside array
if ((oldIndex == newIndex) || (0 > oldIndex) || (oldIndex >= list.Count) || (0 > newIndex) ||
(newIndex >= list.Count)) return;
// local variables
var i = 0;
T tmp = list[oldIndex];
// move element down and shift other elements up
if (oldIndex < newIndex)
{
for (i = oldIndex; i < newIndex; i++)
{
list[i] = list[i + 1];
}
}
// move element up and shift other elements down
else
{
for (i = oldIndex; i > newIndex; i--)
{
list[i] = list[i - 1];
}
}
// put element from position 1 to destination
list[newIndex] = tmp;
}
List <T> .Remove () et List <T> .RemoveAt () ne renvoient pas l'élément en cours de suppression.
Par conséquent, vous devez utiliser ceci:
var item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);
Insérez l'élément actuellement à oldIndex
pour qu'il soit à newIndex
, puis supprimez l'instance d'origine.
list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);
Vous devez tenir compte du fait que l'index de l'élément que vous souhaitez supprimer peut changer en raison de l'insertion.
J'ai créé une méthode d'extension pour déplacer des éléments dans une liste.
Un index ne doit pas être déplacé si nous déplaçons un élément existant , car nous déplaçons un élément vers un existant position d'index dans la liste.
Le cas Edge auquel @Oliver fait référence ci-dessous (déplacer un élément à la fin de la liste) provoquerait en réalité l'échec des tests, mais cela est voulu par la conception même. Pour insérer un nouvel élément à la fin de la liste, nous appelons simplement List<T>.Add
. list.Move(predicate, list.Count)
devrait échouer car cette position d'index n'existe pas avant le déplacement.
Dans tous les cas, j'ai créé deux méthodes d'extension supplémentaires, MoveToEnd
et MoveToBeginning
, dont on peut trouver la source ici .
/// <summary>
/// Extension methods for <see cref="System.Collections.Generic.List{T}"/>
/// </summary>
public static class ListExtensions
{
/// <summary>
/// Moves the item matching the <paramref name="itemSelector"/> to the <paramref name="newIndex"/> in a list.
/// </summary>
public static void Move<T>(this List<T> list, Predicate<T> itemSelector, int newIndex)
{
Ensure.Argument.NotNull(list, "list");
Ensure.Argument.NotNull(itemSelector, "itemSelector");
Ensure.Argument.Is(newIndex >= 0, "New index must be greater than or equal to zero.");
var currentIndex = list.FindIndex(itemSelector);
Ensure.That<ArgumentException>(currentIndex >= 0, "No item was found that matches the specified selector.");
// Copy the current item
var item = list[currentIndex];
// Remove the item
list.RemoveAt(currentIndex);
// Finally add the item at the new index
list.Insert(newIndex, item);
}
}
[Subject(typeof(ListExtensions), "Move")]
public class List_Move
{
static List<int> list;
public class When_no_matching_item_is_found
{
static Exception exception;
Establish ctx = () => {
list = new List<int>();
};
Because of = ()
=> exception = Catch.Exception(() => list.Move(x => x == 10, 10));
It Should_throw_an_exception = ()
=> exception.ShouldBeOfType<ArgumentException>();
}
public class When_new_index_is_higher
{
Establish ctx = () => {
list = new List<int> { 1, 2, 3, 4, 5 };
};
Because of = ()
=> list.Move(x => x == 3, 4); // move 3 to end of list (index 4)
It Should_be_moved_to_the_specified_index = () =>
{
list[0].ShouldEqual(1);
list[1].ShouldEqual(2);
list[2].ShouldEqual(4);
list[3].ShouldEqual(5);
list[4].ShouldEqual(3);
};
}
public class When_new_index_is_lower
{
Establish ctx = () => {
list = new List<int> { 1, 2, 3, 4, 5 };
};
Because of = ()
=> list.Move(x => x == 4, 0); // move 4 to beginning of list (index 0)
It Should_be_moved_to_the_specified_index = () =>
{
list[0].ShouldEqual(4);
list[1].ShouldEqual(1);
list[2].ShouldEqual(2);
list[3].ShouldEqual(3);
list[4].ShouldEqual(5);
};
}
}
Je m'attendrais soit:
// Makes sure item is at newIndex after the operation
T item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);
... ou:
// Makes sure relative ordering of newIndex is preserved after the operation,
// meaning that the item may actually be inserted at newIndex - 1
T item = list[oldIndex];
list.RemoveAt(oldIndex);
newIndex = (newIndex > oldIndex ? newIndex - 1, newIndex)
list.Insert(newIndex, item);
... ferait l'affaire, mais je n'ai pas de VS sur cette machine à vérifier.
Manière la 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 savoir où va l'élément list[newIndex]
, 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 aucune insertion/suppression de liste.