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

发布于 2024-07-06 19:00:14 字数 322 浏览 11 评论 0原文

我有一本字典,就像

Dictionary<Foo,String> fooDict

我逐步浏览字典中的所有内容一样,例如,

foreach (Foo foo in fooDict.Keys)
    MessageBox.show(fooDict[foo]);

它按照将 foo 添加到字典中的顺序执行此操作,因此添加的第一个项目是返回的第一个 foo 。

如何更改基数,例如,添加的第三个 foo 将是返回的第二个 foo? 换句话说,我想改变它的“索引”。

I've got a dictionary, something like

Dictionary<Foo,String> fooDict

I step through everything in the dictionary, e.g.

foreach (Foo foo in fooDict.Keys)
    MessageBox.show(fooDict[foo]);

It does that in the order the foos were added to the dictionary, so the first item added is the first foo returned.

How can I change the cardinality so that, for example, the third foo added will be the second foo returned? In other words, I want to change its "index."

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

淡水深流 2024-07-13 19:00:14

如果您阅读 MSDN 上的文档,您会看到以下内容:

“返回项目的顺序未定义。”

您无法保证顺序,因为字典不是列表或数组。 它意味着通过键查找值,任何迭代值的能力只是一种方便,但顺序不是您应该依赖的行为。

If you read the documentation on MSDN you'll see this:

"The order in which the items are returned is undefined."

You can't gaurantee the order, because a Dictionary is not a list or an array. It's meant to look up a value by the key, and any ability to iterate values is just a convenience but the order is not behavior you should depend on.

苄①跕圉湢 2024-07-13 19:00:14

您可能对 OrderedDicationary类来自 System .Collections.Specialized 命名空间。

如果你看看最底部的评论,就会发现来自 MSFT 的人发布了这个有趣的注释:

这个类型实际上是错误命名的; 它本身不是一个“有序”字典,而是一个“索引”字典。 尽管目前这种类型没有等效的通用版本,但如果我们将来添加一个,我们很可能会命名为“IndexedDictionary”类型。

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

You may be interested in the OrderedDicationary class that comes in System.Collections.Specialized namespace.

If you look at the comments at the very bottom, someone from MSFT has posted this interesting note:

This type is actually misnamed; it is not an 'ordered' dictionary as such, but rather an 'indexed' dictionary. Although, today there is no equivalent generic version of this type, if we add one in the future it is likely that we will name such as type 'IndexedDictionary'.

I think it would be trivial to derive from this class and make a generic version of OrderedDictionary.

墨落画卷 2024-07-13 19:00:14

没有在该领域接受过充分的教育来正确回答这个问题,但我感觉字典根据键对值进行排序,以便执行快速键搜索。 这表明字典是根据键比较按键值排序的。 但是,查看 object 方法,我假设它们使用哈希码来比较不同的对象,因为对键使用的类型没有要求。 这只是一个猜测。 更有知识的人应该填写更多细节。

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

I am not fully educated in the domain to properly answer the question, but I have a feeling that the dictionary sorts the values according to the key, in order to perform quick key search. This would suggest that the dictionary is sorted by key values according to key comparison. However, looking at object methods, I assume they are using hash codes to compare different objects considering there is no requirement on the type used for keys. This is only a guess. Someone more knowledgey should fill in with more detail.

Why are you interested in manipulating the "index" of a dictionary when its purpose is to index with arbitrary types?

留蓝 2024-07-13 19:00:14

我不知道是否有人会觉得这有用,但这就是我最终弄清楚的。 它似乎有效(我的意思是它不会抛出任何异常),但距离测试它是否如我希望的那样有效还有很长的路要走。 不过,我以前也做过类似的事情。

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

I don't know if anyone will find this useful, but here's what I ended up figuring out. It seems to work (by which I mean it doesn't throw any exceptions), but I'm still a ways away from being able to test that it works as I hope it does. I have done a similar thing before, though.

        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);
        }
    }
£噩梦荏苒 2024-07-13 19:00:14

简而言之,因为字典“代表键和值的集合”,所以不应该有任何方法。 这并不意味着任何排序。 您可能发现的任何 hack 都超出了类的定义,并且可能会发生更改。

您可能应该首先问自己在这种情况下是否真的需要字典,或者您是否可以使用键值对列表。

否则,这样的东西可能会有用:

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 结构中转换出来

The short answer is that there shouldn't be a way since a Dictionary "Represents a collection of keys and values." which does not imply any sort of ordering. Any hack you might find is outside the definition of the class and may be liable to change.

You should probably first ask yourself if a Dictionary is really called for in this situation, or if you can get away with using a List of KeyValuePairs.

Otherwise, something like this might be useful:

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

    }


}

With client code looking something like this:

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

UPDATE: For some reason it won't let me comment on my own answer.

Anyways, IndexableDictionary is different from OrderedDictionary in that

  1. "The elements of an OrderedDictionary are not sorted in any way." So foreach's would not pay attention to the numerical indices
  2. It is strongly typed, so you don't have to mess around with casting things out of DictionaryEntry structs
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文