C# 通用列表 - 在列表中移动一个项目

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/450233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 03:50:19  来源:igfitidea点击:

Generic List - moving an item within the list

c#.netgenericslist

提问by Richard Ev

So I have a generic list, and an oldIndexand a newIndexvalue.

所以我有一个通用列表,以及一个oldIndex和一个newIndex值。

I want to move the item at oldIndex, to newIndex...as simply as possible.

我想尽可能简单地将 , 处的项目移动oldIndexnewIndex...。

Any suggestions?

有什么建议?

Note

笔记

The item should be end up between the items at (newIndex - 1)and newIndexbeforeit was removed.

该项目应该它被删除之前(newIndex - 1)newIndex之前的项目之间结束。

采纳答案by jpierson

I know you said "generic list" but you didn't specify that you needed to use the List(T)class so here is a shot at something different.

我知道你说的是“通用列表”,但你没有指定你需要使用List(T)类,所以这里有一些不同的东西。

The ObservableCollection(T)class has a Move methodthat does exactly what you want.

的ObservableCollection(T)类有一个Move方法,你想要做什么。

public void Move(int oldIndex, int newIndex)

Underneath it is basicallyimplemented like this.

在它下面基本上是这样实现的。

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

So as you can see the swap method that others have suggested is essentially what the ObservableCollectiondoes in it's own Move method.

所以你可以看到其他人建议的交换方法本质上就是ObservableCollection在它自己的 Move 方法中所做的。

UPDATE 2015-12-30:You can see the source code for the Moveand MoveItemmethods in corefx now for yourself without using Reflector/ILSpy since .NET is open source.

更新 2015-12-30:您现在可以在 corefx 中查看MoveMoveItem方法的源代码,而无需使用 Reflector/ILSpy,因为 .NET 是开源的。

回答by Aaron Maenpaa

I would expect either:

我希望:

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

... or:

... 或者:

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

... would do the trick, but I don't have VS on this machine to check.

...会做的伎俩,但我在这台机器上没有 VS 来检查。

回答by Garry Shutler

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

回答by Megacan

Insert the item currently at oldIndexto be at newIndexand then remove the original instance.

插入该项目目前oldIndex是在newIndex然后删除原始实例。

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

You have to take into account that the index of the item you want to remove may change due to the insertion.

您必须考虑到要删除的项目的索引可能会因插入而发生变化。

回答by M4N

List<T>.Remove() and List<T>.RemoveAt() do not return the item that is being removed.

List<T>.Remove() 和 List<T>.RemoveAt() 不返回被删除的项目。

Therefore you have to use this:

因此你必须使用这个:

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

回答by bruno conde

Simplest way:

最简单的方法:

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

EDIT

编辑

The question isn't very clear ... Since we don't care where the list[newIndex]item goes I think the simplest way of doing this is as follows (with or without an extension method):

问题不是很清楚......因为我们不关心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;
    }

This solution is the fastest because it doesn't involve list insertions/removals.

此解决方案是最快的,因为它不涉及列表插入/删除。

回答by Ben Foster

I created an extension method for moving items in a list.

我创建了一个用于在列表中移动项目的扩展方法。

An index should not shift if we are moving an existingitem since we are moving an item to an existingindex position in the list.

如果我们正在移动现有项目,则索引不应移动,因为我们将项目移动到列表中的现有索引位置。

The edge case that @Oliver refers to below (moving an item to the end of the list) would actually cause the tests to fail, but this is by design. To insert a newitem at the end of the list we would just call List<T>.Add. list.Move(predicate, list.Count)shouldfail since this index position does not exist before the move.

@Oliver 在下面提到的边缘情况(将项目移动到列表的末尾)实际上会导致测试失败,但这是设计使然。要在列表末尾插入一个项目,我们只需调用List<T>.Add. list.Move(predicate, list.Count)应该失败,因为该索引位置在移动之前不存在。

In any case, I've created two additional extension methods, MoveToEndand MoveToBeginning, the source of which can be found here.

无论如何,我已经创建了两个额外的扩展方法MoveToEndMoveToBeginning,其来源可以在这里找到。

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

回答by Francisco

I know this question is old but i adapted THISresponse of javascript code to C#. Hope it helps

我知道这个问题很老,但我将javascript 代码的这个响应改编为 C#。希望能帮助到你

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

回答by Allan Harper

This is how I implemented a move element extension method. It handles moving before/after and to the extremes for elements pretty well.

这就是我实现移动元素扩展方法的方式。它可以很好地处理元素的前后移动和极端移动。

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

回答by Richard Aguirre

Is more simple guys just do this

更简单的人就这样做

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

Do the same with MoveDown but change the if for "if (ind !=Concepts.Count())" and the Concepts.Insert(ind+1,item.ToString());

对 MoveDown 执行相同操作,但更改 if 为“if (ind !=Concepts.Count())”和 Concepts.Insert(ind+1,item.ToString());