通过数字索引访问Dictionary.Keys键

时间:2020-03-05 18:38:12  来源:igfitidea点击:

我使用的是Dictionary <string,int>,其中int是键的计数。

现在,我需要访问字典中最后插入的键,但是我不知道它的名称。显而易见的尝试:

int LastCount = mydict[mydict.keys[mydict.keys.Count]];

不起作用,因为Dictionary.Keys没有实现[] -indexer。

我只是想知道是否有类似的课程?我考虑过使用堆栈,但是只存储一个字符串。我现在可以创建自己的结构,然后使用Stack <MyStruct>,但是我想知道是否还有另一种选择,本质上是在Keys上实现[] -indexer的Dictionary?

解决方案

回答

我们可以始终这样做:

string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]

但是我不推荐它。不能保证最后插入的键将在数组的末尾。 MSDN上的密钥顺序未指定,并且可能会发生变化。在我的简短测试中,它似乎确实按插入顺序排列,但最好还是像堆栈一样构建适当的簿记功能-正如我们所建议的(尽管我认为我们并不需要基于结构其他语句)或者单个变量缓存(如果我们只需要知道最新的密钥)。

回答

我不知道这是否行得通,因为我非常确定密钥没有按照添加顺序存储,但是我们可以将KeysCollection强制转换为列表,然后获取列表中的最后一个密钥...但值得一看。

我唯一能想到的是将密钥存储在查找列表中,然后再将密钥添加到列表中,然后再将其添加到字典中……这不太好。

回答

我认为我们可以做这样的事情,语法可能是错误的,有一段时间没有使用Cin了
获取最后一个项目

Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();

还是使用Max而不是Last来获得最大值,我不知道哪个更适合代码。

回答

我同意帕特里克回答的第二部分。即使在某些测试中似乎保持插入顺序,文档(以及字典和哈希的正常行为)也明确指出未指定顺序。

我们只是在根据键的顺序询问问题。确保添加自己的簿记(如Patrick所说,最后添加的键只是一个变量)。另外,不要被字典上的所有方法(例如Last和Max)所吸引,因为这些方法可能与键比较器有关(我不确定)。

回答

我们对问题的措辞使我相信词典中的int包含该项在词典中的"位置"。从断言不是按添加顺序存储键的断言来看,如果这是正确的话,这意味着keys.Count(如果使用基于零的数字,则为.Count 1)应该始终是最后输入的密钥的编号?

如果是正确的话,有什么理由不能代替使用Dictionary <int,string>以便可以使用mydict [mydict.Keys.Count]?

回答

为什么不扩展字典类以添加最后一个插入键的属性。像下面这样的东西?

public class ExtendedDictionary : Dictionary<string, int>
{
    private int lastKeyInserted = -1;

    public int LastKeyInserted
    {
        get { return lastKeyInserted; }
        set { lastKeyInserted = value; }
    }

    public void AddNew(string s, int i)
    {
        lastKeyInserted = i;

        base.Add(s, i);
    }
}

回答

我们可以使用OrderedDictionary。

Represents a collection of key/value
  pairs that are accessible by the key
  or index.

回答

字典是哈希表,因此我们不知道插入顺序!

如果我们想知道最后插入的键,建议我们将Dictionary扩展为包含LastKeyInserted值。

例如。:

public MyDictionary<K, T> : IDictionary<K, T>
{
    private IDictionary<K, T> _InnerDictionary;

    public K LastInsertedKey { get; set; }

    public MyDictionary()
    {
        _InnerDictionary = new Dictionary<K, T>();
    }

    #region Implementation of IDictionary

    public void Add(KeyValuePair<K, T> item)
    {
        _InnerDictionary.Add(item);
        LastInsertedKey = item.Key;

    }

    public void Add(K key, T value)
    {
        _InnerDictionary.Add(key, value);
        LastInsertedKey = key;
    }

    .... rest of IDictionary methods

    #endregion

}

但是,当我们使用.Remove()时,我们会遇到问题,因此要解决此问题,我们将必须保留插入键的有序列表。

回答

万一我们决定使用容易破损的危险代码,此扩展功能将根据其内部索引(对于Mono和.NET当前似乎位于同一索引中)从'Dictionary <K,V>中获取密钥。通过枚举Keys`属性获得的顺序)。

最好使用Linq:dict.Keys.ElementAt(i),但是该函数将迭代O(N);以下是O(1),但会降低反射性能。

using System;
using System.Collections.Generic;
using System.Reflection;

public static class Extensions
{
    public static TKey KeyByIndex<TKey,TValue>(this Dictionary<TKey, TValue> dict, int idx)
    {
        Type type = typeof(Dictionary<TKey, TValue>);
        FieldInfo info = type.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance);
        if (info != null)
        {
            // .NET
            Object element = ((Array)info.GetValue(dict)).GetValue(idx);
            return (TKey)element.GetType().GetField("key", BindingFlags.Public | BindingFlags.Instance).GetValue(element);
        }
        // Mono:
        info = type.GetField("keySlots", BindingFlags.NonPublic | BindingFlags.Instance);
        return (TKey)((Array)info.GetValue(dict)).GetValue(idx);
    }
};