Общий список - перемещение элемента в списке

Итак, у меня есть общий список и значение oldIndex и newIndex.

Я хочу переместить элемент в oldIndex, newIndex... как можно проще.

Любые предложения?

Примечание

Элемент должен находиться в конце между элементами (newIndex - 1) и newIndex до его удаления.

Ответ 1

Я знаю, что вы сказали "общий список", но вы не указали, что вам нужно использовать класс List (T), поэтому здесь вы можете сделать что-то другое.

Класс ObservableCollection (T) имеет метод перемещения, который делает именно то, что вы хотите.

public void Move(int oldIndex, int newIndex)

Под ним в основном реализовано подобное.

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

Итак, как вы можете видеть метод подкачки, который другие предложили, по сути, это то, что ObservableCollection делает в нем собственный метод Move.

UPDATE 2015-12-30: Вы можете увидеть исходный код Move и MoveItem в corefx теперь для себя, не используя Reflector/ILSpy, поскольку .NET является открытым исходным кодом.

Ответ 2

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

Ответ 3

Я знаю, что этот вопрос старый, но я адаптировал ЭТО ответ javascript-кода на С#. Надеюсь, что это поможет.

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

Ответ 4

Список <T> .Remove() и List <T> .RemoveAt() не возвращают элемент, который удаляется.

Поэтому вы должны использовать это:

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

Ответ 5

Я создал метод расширения для перемещения элементов в списке.

Индекс не должен меняться, если мы перемещаем существующий элемент, так как мы перемещаем элемент в существующую позицию индекса в списке.

Края, которую @Oliver ссылается ниже (перемещение элемента в конец списка), фактически приведет к сбою тестов, но это по дизайну. Чтобы вставить новый элемент в конец списка, мы просто вызываем List<T>.Add. list.Move(predicate, list.Count) должен выйти из строя, поскольку эта позиция индекса не существует до перемещения.

В любом случае, я создал два дополнительных метода расширения, MoveToEnd и MoveToBeginning, источник которых можно найти здесь.

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

Ответ 6

Что-то вроде этого:

List<object> l;
l.Insert(newIndex, l[oldIndex]);
if(newIndex <= oldIndex) ++oldIndex;
l.RemoveAt(oldIndex);

EDIT: Принимая во внимание сдвиг индекса, надейтесь, что это будет правильно. (tks для комментариев)

Ответ 7

Я ожидал бы:

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

... или:

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

... сделал бы трюк, но у меня нет VS на этой машине, чтобы проверить.

Ответ 8

Простейший способ:

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

ИЗМЕНИТЬ

Вопрос не очень ясен... Так как нам все равно, где находится элемент list[newIndex], я думаю, что самый простой способ сделать это следующий (с использованием метода расширения или без него):

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

Это решение является самым быстрым, поскольку оно не включает в себя вставки/удаления списка.

Ответ 9

Вот как я применил метод расширения элемента перемещения. Он обрабатывает перемещение до/после и до крайностей для элементов довольно хорошо.

public static void MoveElement<T>(this IList<T> 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);
  }
}

Ответ 10

Более простые парни просто делают это

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

Сделайте то же самое с MoveDown, но измените if для if if (ind!= Concepts.Count()) и Concepts.Insert(ind + 1, item.ToString());