SortedList不能正确地删除和添加项目

本文关键字:添加 项目 删除 不能 正确地 SortedList | 更新日期: 2023-09-27 18:12:08

我遇到了SortedList的问题,其中两个方法给出了两个不同的结果。

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

结果不是那么明显。我将使用数字而不是抽象的字母来更好地说明正在发生的事情。

itemPos被设置为5。好的!接下来我们试着从这个索引中再得到这个项目,但是没有。它返回null。当然,这不会马上发生。在此之前调用此代码。

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

要移动已排序列表中的项,我们必须再次删除和添加项。好的!调试表明,操作进行得非常顺利,我的项目现在有了索引5,我把它从索引4移到了索引5。其中索引5在MoveItem方法之前为空

还是空的?在此操作之前,我有一个索引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。这让我很困惑,我把一切都搞混了。就像Christoph说的。最好使用您自己的列表,您可以根据需要使用它或深入阅读文档

SortedList不能正确地删除和添加项目

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

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

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

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

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

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

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

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

…集合中只有一个条目,MoveItem将删除/添加,因此不会改变计数。因此IndexOfValue可以只能返回0(或-1,如果没有找到)。

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

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

注意,TryGetValue使用,而不是索引—所以这一行:

Items.TryGetValue(itemPos, out item);

…这将是一个非常奇怪的问题。

如果使用不同的键类型(例如字符串),所有这些都更容易看到。这样你就不会把键和索引搞混了,因为这两种类型是不同的,编译器不会让你用其中一种来代替另一种。