Lista genérica: mover un elemento dentro de la lista

Entonces tengo una lista genérica y un valor oldIndex y newIndex .

Quiero mover el elemento a oldIndex , a newIndex … tan simple como sea posible.

¿Alguna sugerencia?

Nota

El ítem debe terminar entre los ítems en (newIndex - 1) y newIndex antes de ser eliminado.

Sé que dijiste “lista genérica” ​​pero no especificaste que tenías que usar la clase List (T) así que aquí hay una oportunidad de algo diferente.

La clase ObservableCollection (T) tiene un método Move que hace exactamente lo que usted desea.

 public void Move(int oldIndex, int newIndex) 

Debajo, básicamente se implementa así.

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

Entonces, como puede ver, el método de intercambio que otros han sugerido es esencialmente lo que hace ObservableCollection en su propio método Move.

ACTUALIZACIÓN 2015-12-30: Ahora puede ver el código fuente de los métodos Move y MoveItem en corefx sin usar Reflector / ILSpy, ya que .NET es de código abierto.

 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); 

Sé que esta pregunta es antigua pero adapté ESTA respuesta del código de JavaScript a C #. Espero eso ayude

  public static void Move(this List 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 .Remove () y List .RemoveAt () no devuelven el elemento que se está eliminando.

Por lo tanto, debes usar esto:

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

Creé un método de extensión para mover elementos en una lista.

Un índice no debe cambiar si estamos moviendo un elemento existente , ya que estamos moviendo un elemento a una posición de índice existente en la lista.

El caso límite al que se refiere @Oliver a continuación (mover un elemento al final de la lista) en realidad haría que fallaran las pruebas, pero esto es por diseño. Para insertar un nuevo elemento al final de la lista, simplemente llamaríamos a List.Add . list.Move(predicate, list.Count) debería fallar dado que esta posición de índice no existe antes del movimiento.

En cualquier caso, he creado dos métodos de extensión adicionales, MoveToEnd y MoveToBeginning , MoveToBeginning origen se puede encontrar aquí .

 ///  /// Extension methods for  ///  public static class ListExtensions { ///  /// Moves the item matching the  to the  in a list. ///  public static void Move(this List list, Predicate 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(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 list; public class When_no_matching_item_is_found { static Exception exception; Establish ctx = () => { list = new List(); }; Because of = () => exception = Catch.Exception(() => list.Move(x => x == 10, 10)); It Should_throw_an_exception = () => exception.ShouldBeOfType(); } public class When_new_index_is_higher { Establish ctx = () => { list = new List { 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 { 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); }; } } 

Inserte el elemento actualmente en oldIndex para que esté en newIndex y luego elimine la instancia original.

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

Debe tener en cuenta que el índice del artículo que desea eliminar puede cambiar debido a la inserción.

Yo esperaría cualquiera:

 // Makes sure item is at newIndex after the operation T item = list[oldIndex]; list.RemoveAt(oldIndex); list.Insert(newIndex, item); 

… o:

 // 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); 

… haría el truco, pero no tengo VS en esta máquina para verificar.

La manera más simple:

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

EDITAR

La pregunta no es muy clara … Dado que no nos importa dónde va el elemento de la list[newIndex] , creo que la forma más sencilla de hacerlo es la siguiente (con o sin un método de extensión):

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

Esta solución es la más rápida porque no involucra inserciones / eliminaciones de listas.

Es más simple chicos solo hacen esto

  public void MoveUp(object item,List Concepts){ int ind = Concepts.IndexOf(item.ToString()); if (ind != 0) { Concepts.RemoveAt(ind); Concepts.Insert(ind-1,item.ToString()); obtenernombres(); NotifyPropertyChanged("Concepts"); }} 

Haga lo mismo con MoveDown pero cambie if para “if (ind! = Concepts.Count ())” y los Concepts.Insert (ind + 1, item.ToString ());

Así es como implementé un método de extensión de elementos de movimiento. Se maneja moviendo antes / después y hasta los extremos para elementos bastante bien.

 public static void MoveElement(this IList list, int fromIndex, int toIndex) { if (!fromIndex.InRange(0, list.Count - 1)) { throw new ArgumentException("From index is invalid"); } if (!toIndex.InRange(0, list.Count - 1)) { throw new ArgumentException("To index is invalid"); } if (fromIndex == toIndex) return; var element = list[fromIndex]; if (fromIndex > toIndex) { list.RemoveAt(fromIndex); list.Insert(toIndex, element); } else { list.Insert(toIndex + 1, element); list.RemoveAt(fromIndex); } }