SortedList 没有正确删除和添加项目

SortedList does not remove and adding items correctly

我在使用 SortedList 时遇到问题,其中 2 个方法给出了 2 个不同的结果。

//Item Data is one of this sortedList item
var itemPos = Items.IndexOfValue(ItemData);
Item item;
Items.TryGetValue(itemPos, out item);

结果不是很明显。我将对数字而不是摘要字母进行操作,以更好地说明正在发生的事情。

itemPos 设置为 5。好的!接下来我们尝试从这个索引中再次获取这个项目但是没有。它 returns 无效。当然,这不会立即发生。在此之前调用此代码。

    public void MoveItem(int indexFrom, int indexWhere)
    {
        Item itemToSawp;
        Items.TryGetValue(indexFrom, out itemToSawp);
        Items.Remove(indexFrom);
        Items.Add(indexWhere, itemToSawp);
    }

要移动排序列表中的项目,我们必须再次删除和添加项目。行!调试说操作进行得很顺利,我的项目现在有索引 5 我将它从索引 4 移开。在方法 MoveItem 之前索引 5 为空。

还是空的?在那次操作之前,我的索引 5 充满了东西,我调用了简单的 Items.Remove(5);

但现在发生了我之前描述的情况。

值得注意的是,只有当我在索引中向上移动项目时才会发生这种情况,从 4-5 看。当我从 5-4 移动时,一切正常。

你知道这里发生了什么吗?我正在使用 .NET 3.5

完整代码

using System;
using System.Collections.Generic;

class Program
{
    static SortedList<int, ItemData> Items = new SortedList<int, ItemData>();

    static void Main(string[] args)
    {
        var Foo = new ItemData();
        Items.Add(0, Foo);
        Items.Add(1, new ItemData());
        Items.Remove(1);
        MoveItem(0, 1);
        var itemPos = Items.IndexOfValue(Foo);
        Console.WriteLine(itemPos);
        //Console should return 1 i think
        ItemData item;
        Items.TryGetValue(itemPos, out item);
    }

    public static void MoveItem(int indexFrom, int indexWhere)
    {
        ItemData itemToSawp;
        Items.TryGetValue(indexFrom, out itemToSawp);
        Items.Remove(indexFrom);
        Items.Add(indexWhere, itemToSawp);
    }

    class ItemData
    {

    }
}

编辑:这有点令人困惑,但是!索引器(看它的名字:P)作为参数 KEY 而不是 INDEX。这就是让我感到困惑的原因,我混淆了一切。正如克里斯托夫所说。最好使用您自己的列表,您可以根据需要使用它或深入阅读文档。

据我所知,您对 SortedList 的概念理解不正确。当您有与键关联的对象,并且键是可排序的,并且它们的顺序与性能、某种算法等相关时,使用 SortedLists。例如,考虑一场马拉松比赛,您可以根据完成时间将 Runner 对象存储在 SortedList 中。无论如何,记住键是一个可排序的值,每个键都与一个任意值对象相关联。

现在,我在您的代码中观察到一些问题:

  • 在第一个代码框中,第 2 行,您找到一个值对象的索引。这违背了使用 SortedList 的目的,因为该操作很慢,而使用键查找值却很快(通过内部哈希表等)。
  • 在第一个代码框中,第 4 行,您调用了 TryGetValue。查看定义,第一个参数是键,而不是 SortedList 中的索引。所以这个例子从语义的角度来看是错误的。

关于在 SortedList 中移动项目(代码框 2),这将始终需要使用原始键删除值对象,然后添加具有不同键(通常更大或更小)的值对象。但话又说回来,我不明白你为什么要在 SortedList 中四处移动项目。重点是您可以简单地添加与可排序键关联的值对象,SortedList 会自动为您对所有这些对象进行排序。

我觉得您可能想要考虑一个常规的 List 对象,或者如果大小是固定的或有限的,甚至只是一个数组。然后你得到你所有的索引语义并且可以交换项目,如果那是你的算法真正想要做的。

编辑:我刚看到完整的代码。我上面的一般建议是有效的。完整示例中的问题是您将键与索引混淆了。在 MoveItem(0,1) 之后,Foo 对象使用键 1 注册,但由于 SortedList 中只有一个条目,因此它位于索引 0,您可以使用 IndexOfValue(慢速操作)获得该索引。然后,当您执行 TryGetValue 时,您实际上会查找键为 0 的条目,该条目不存在。您错误地假设 TryGetValue 会将索引作为参数。

您混淆了条目的 key 和条目的 index。您的 MoveItem 方法只是更改与值关联的键(通过删除旧条目并创建新条目)。在这些行之后:

Items.Add(0, Foo);
Items.Add(1, new ItemData());
Items.Remove(1);

...集合中只有一个条目,MoveItem 将 remove/add,因此不会更改计数。因此 IndexOfValue 只能 return 0(如果找不到则为 -1)。

要获得 1,您需要找到与值相关联的 key,而不是索引。例如:

int index = Items.IndexOfValue(Foo);
int key = Items.Keys[index];
Console.WriteLine("Key = {0}", key); // Prints 1

请注意 TryGetValue 采用 ,而不是索引 - 所以这一行:

Items.TryGetValue(itemPos, out item);

...会很奇怪。

如果您使用不同的密钥类型,例如一个字符串。然后你就不会混淆键和索引,因为类型不同,编译器不会让你在你想要的地方使用一个。