在C#字典中更改项的基数

4

我有一个类似字典的东西,就像这样:

Dictionary<Foo,String> fooDict

我循环遍历字典中的所有内容,例如:
foreach (Foo foo in fooDict.Keys)
    MessageBox.show(fooDict[foo]);

它按照添加到字典中的顺序执行,因此添加的第一项是返回的第一个foo。
我如何更改基数,使例如添加的第三个foo成为第二个返回的foo?换句话说,我想改变它的“索引”。
5个回答

8
如果您阅读MSDN上的文档,您会看到以下内容:
“返回项的顺序是未定义的。”
您无法保证顺序,因为字典不是列表或数组。它的目的是通过键查找值,并且任何迭代值的能力仅仅是一种方便,但您不应该依赖于顺序行为。

在.NET中有一个替代对象,它允许您在字典中保持顺序,请参见:https://dev59.com/EUXRa4cB1Zd3GeqPqUzy - Eric Schoonover

5

您可能会对OrderedDicationary类感兴趣,它位于System.Collections.Specialized命名空间中。

如果您查看底部的注释,来自MSFT的某人发布了这个有趣的说明:

实际上,这种类型的名称是错误的;它并不是一个“有序”的字典,而是一个“索引”的字典。虽然今天没有等效的泛型版本,但如果我们在未来添加一个,则很可能将此类命名为“IndexedDictionary”。

我认为从这个类派生并制作一个通用版本的OrderedDictionary将是微不足道的。


哇,我甚至不知道这种东西的存在。谢谢! - Asmor

0

我在这个领域并不是完全受过教育,无法给出恰当的答案,但我有一种感觉,字典会根据键值对值进行排序,以便快速搜索键。这表明字典是按照键比较排序的。然而,从对象方法来看,我认为它们使用哈希码来比较不同的对象,考虑到键使用的类型没有要求。这只是一个猜测。更有知识的人应该用更多的细节来填补这个空缺。

当字典的目的是用任意类型进行索引时,您为什么对操作字典的“索引”感兴趣呢?


我的字典实际上是 Dictionary<ListViewItem,CustomObject>我想让用户重新排序列表视图中的项目时,也重新排序字典中的项目,以便它们按照相同的顺序排列。 - Asmor

0

我不知道是否有人会发现这个有用,但这是我最终想出的解决方案。它似乎可以工作(我的意思是它不会抛出任何异常),但我还有很长的路要走才能测试它是否按照我所希望的那样工作。虽然我以前做过类似的事情。

        public void sortSections()
    {
        //OMG THIS IS UGLY!!!
        KeyValuePair<ListViewItem, TextSection>[] sortable = textSecs.ToArray();
        IOrderedEnumerable<KeyValuePair<ListViewItem, TextSection>> sorted = sortable.OrderBy(kvp => kvp.Value.cardinality);

        foreach (KeyValuePair<ListViewItem, TextSection> kvp in sorted)
        {
            TextSection sec = kvp.Value;
            ListViewItem key = kvp.Key;

            textSecs.Remove(key);
            textSecs.Add(key, sec);
        }
    }

你“可能”没问题,但是像我所说的,顺序不能保证。一旦需要调整大小,它就会尝试重新排序。不管怎样,为什么要使用字典? - CodeRedick
希望将ListView项与自定义对象关联。在我正在工作的项目中,我已经做了几次了,但这是第一次基数真正有影响。 - Asmor

0
简短的回答是,由于字典“表示键和值的集合”,因此不应该有任何排序方式。任何您可能找到的黑客方法都在类的定义之外,可能会发生变化。
您应该首先问自己,在这种情况下是否真的需要使用字典,或者是否可以使用KeyValuePairs列表来解决问题。
否则,像这样的东西可能会有用:
public class IndexableDictionary<T1, T2> : Dictionary<T1, T2>
{
    private SortedDictionary<int, T1> _sortedKeys;

    public IndexableDictionary()
    {
        _sortedKeys = new SortedDictionary<int, T1>();
    }
    public new void Add(T1 key, T2 value)
    {
        _sortedKeys.Add(_sortedKeys.Count + 1, key);
        base.Add(key, value);
    }

    private IEnumerable<KeyValuePair<T1, T2>> Enumerable()
    {
        foreach (T1 key in _sortedKeys.Values)
        {
            yield return new KeyValuePair<T1, T2>(key, this[key]);
        }
    }

    public new IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
    {
        return Enumerable().GetEnumerator();
    }

    public KeyValuePair<T1, T2> this[int index]
    {
        get
        {
            return new KeyValuePair<T1, T2> (_sortedKeys[index], base[_sortedKeys[index]]);
        }
        set
        {
            _sortedKeys[index] = value.Key;
            base[value.Key] = value.Value;
        }

    }


}

客户端代码看起来像这样:

    static void Main(string[] args)
    {
        IndexableDictionary<string, string> fooDict = new IndexableDictionary<string, string>();

        fooDict.Add("One", "One");
        fooDict.Add("Two", "Two");
        fooDict.Add("Three", "Three");

        // Print One, Two, Three
        foreach (KeyValuePair<string, string> kvp in fooDict)
            Console.WriteLine(kvp.Value);



        KeyValuePair<string, string> temp = fooDict[1];
        fooDict[1] = fooDict[2];
        fooDict[2] = temp;


        // Print Two, One, Three
        foreach (KeyValuePair<string, string> kvp in fooDict)
            Console.WriteLine(kvp.Value);

        Console.ReadLine();
    }

更新:由于某些原因,它不允许我在自己的答案上发表评论。

无论如何,IndexableDictionary与OrderedDictionary不同,因为

  1. “OrderedDictionary的元素没有以任何方式排序。” 因此,foreach不会注意数字索引
  2. 它是强类型的,因此您不必烦恼将事物从DictionaryEntry结构中转换出来

这不是基本上在重新创建OrderedDictionary吗? - Eric Schoonover
1
@spoon16:它是强类型的(没有装箱/拆箱性能降低/其他问题),可以通过索引访问。 - Callum Rogers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接