通用列表 - 移动列表中的项目

Ric*_*ett 139 .net c# generics list

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

我想尽可能简单地将项目移动oldIndexnewIndex......

有什么建议?

注意

该项目应该在删除之前(newIndex - 1)newIndex 之前的项目之间结束.

jpi*_*son 123

我知道你说过"通用列表",但是你没有指定你需要使用List(T)类,所以这里是一个不同的镜头.

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

public void Move(int oldIndex, int newIndex)
Run Code Online (Sandbox Code Playgroud)

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

T item = base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, item);
Run Code Online (Sandbox Code Playgroud)

因此,您可以看到其他人建议的交换方法基本上就是ObservableCollection在其自己的Move方法中所做的工作.

UPDATE二○一五年十二月三十○日:你可以看到在源代码中移动移动选项中corefx方法现在为自己没有使用反射/自.NET ILSpy是开源的.

  • 我想知道为什么这个没有在List <T>上实现,任何人都可以对此有所了解? (25认同)
  • 有人可以解释,为什么没有目的地索引转移(如果它大于源索引)确实? (4认同)
  • 通用列表和 List(T) 类有什么区别?我以为他们是一样的:( (2认同)
  • “通用列表”可以指.NET 中的任何类型的列表或集合,例如数据结构,其中可以包括 ObservableCollection(T) 或可以实现 _listy_ 接口的其他类,例如 IList/ICollection/IEnumerable。 (2认同)

Gar*_*ler 117

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);
Run Code Online (Sandbox Code Playgroud)

  • 如果列表中有两个项目副本,其中一个在oldIndex之前发生,则解决方案会中断.你应该使用RemoveAt来确保你得到正确的. (8认同)
  • 的确,偷偷摸摸的边缘情况 (6认同)
  • 我不会使用它,因为它出于多种原因令人困惑。在列表上定义方法 Move(oldIndex,newIndex) 并调用 Move(15,25) 然后 Move(25,15) 不是身份而是交换。此外 Move(15,25) 使项目移动到索引 24 而不是我期望的 25。另外可以通过 temp=item[oldindex]; 来实现交换。项目[旧索引]=项目[新索引];item[newindex]=temp; 这在大型阵列上似乎更有效。Move(0,0) 和 Move(0,1) 也是一样的,这也是奇数。而且 Move(0, Count -1) 不会将项目移动到最后。 (2认同)

小智 9

我知道这个问题已经过时但是我将这个 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;
}
Run Code Online (Sandbox Code Playgroud)


M4N*_*M4N 8

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

因此你必须使用这个:

var item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);
Run Code Online (Sandbox Code Playgroud)


Ben*_*ter 8

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

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

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

无论如何,我创建了两个额外的扩展方法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);
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Oliver 在普通的“List&lt;T&gt;”中,我只需调用“.Add”即可将*新*项目插入到列表的末尾。当“移动”单个项目时,我们永远不会增加索引的原始大小,因为我们只是删除单个项目并重新插入它。如果您单击我的答案中的链接,您将找到“Ensure.Argument”的代码。 (3认同)

Meg*_*can 5

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

list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);
Run Code Online (Sandbox Code Playgroud)

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

  • 您应该在插入之前删除...您的订单可能会导致列表进行分配。 (3认同)