2008-08-07 71 views
134

我正在使用Dictionary<string, int>,其中int是键的计数。通过数字索引访问Dictionary.Keys键

现在,我需要访问字典中最后插入的密钥,但我不知道它的名称。明显的尝试:

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

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

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

+1

发生什么情况,如果你框变量? – 2014-07-29 19:24:22

回答

203

由于@Falanwe在评论中指出,做这样的事情是不正确

int LastCount = mydict.Keys.ElementAt(mydict.Count -1); 

不应取决于在字典键的顺序上。如果您需要订购,则应使用OrderedDictionary,如answer中所述。此页面上的其他答案也很有趣。

6

你总是可以做到这一点:

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

但我不会推荐它。不能保证最后插入的键将在数组的末尾。 Keys on MSDN的订购未指定,可能会更改。在我的非常简短的测试中,它似乎是按照插入的顺序排列的,但是你最好是像堆栈一样建立适当的簿记 - 就像你所建议的那样(尽管我没有看到需要基于你的结构其他语句) - 或者单个变量缓存,如果您只需要知道最新的密钥。

2

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

我能想到的唯一的其他事情就是将键存储在查找列表中,并将键添加到列表中,然后再将它们添加到字典中......这不是很好。

+0

我没有测试代码,但该方法记录在[MSDN] [1]也许是它的另一个版本的框架? [1]:http://msdn.microsoft.com/en-us/library/bb908406.aspx – Juan 2008-08-07 02:13:25

+0

@Juan:上有KeyCollection没有。去年()方法 – lomaxx 2008-08-07 01:23:35

+0

2年晚,但它可能会帮助某人......请参阅下面我对Juan的帖子的回复。 Last()是一个扩展方法。 – SuperOli 2010-11-05 14:08:58

5

我认为你可以做这样的事情,语法可能是错误的,还没有使用C#在一段时间 要得到最后一个项目

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

,或者使用的,而不是最后马克斯获得最大价值,我不知道哪一个更适合你的代码。

+2

我想补充一点,因为“最后的()”是一个扩展方法,你需要在.NET Framework 3.5,并添加“使用System.Linq的”在你的cs文件的顶部。 – SuperOli 2010-11-05 14:07:18

+0

尝试这为最后(当使用Dist 显然:-) KeyValuePair last = oAuthPairs.Last(); 如果(kvp.Key = last.Key!) { _oauth_ParamString = _oauth_ParamString + “&”; } – 2013-06-24 18:23:13

4

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

你只是要求麻烦取决于按键的顺序。加上你自己的簿记(就像帕特里克说的那样,只是最后一个添加键的单个变量)可以肯定。另外,不要被字典中的Last和Max等所有方法所吸引,因为这些方法可能与关键比较器有关(我不太确定)。

3

你说这个问题的方式让我相信词典中的int包含了该词典中的项目“位置”。从断言来看,这些键不是按照它们添加的顺序存储的,如果这是正确的,那将意味着keys.Count(或者.Count - 1,如果您使用的是基于零的)仍然应该始终是最后输入的密钥的数量?

如果这是正确的,是否有任何理由,你不能改为使用字典< INT,字符串>,以便您可以使用mydict [mydict.Keys.Count]?

8

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

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

您正在将lastKeyInserted设置为插入的最后一个值。要么你打算把它设置为最后一个键,要么你需要更好的变量和属性名称。 – Fantius 2011-03-02 00:48:10

+0

呃?不,我不是(?) – Calanus 2011-03-02 11:27:57

56

您可以使用OrderedDictionary

表示键/值 对是由密钥 或索引可访问的集合。

16

字典是一个哈希表,所以你不知道插入的顺序!

如果你想知道最后插入的键,我建议扩展字典以包含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()所以要克服这一点,你将不得不继续插入钥匙的有序列表,你会遇到的问题,但是。

3

如果您决定使用可能会损坏的危险代码,则此扩展功能将根据其内部索引从Dictionary<K,V>中获取密钥(Mono和.NET目前似乎与您的顺序相同通过列举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); 
    } 
}; 
4

如果密钥嵌入在值中,则可以选择KeyedCollection

只需在密封的类中创建一个基本实现即可使用。

所以要代替Dictionary<string, int>(这不是一个很好的例子,因为int没有明确的键)。

private sealed class IntDictionary : KeyedCollection<string, int> 
{ 
    protected override string GetKeyForItem(int item) 
    { 
     // The example works better when the value contains the key. It falls down a bit for a dictionary of ints. 
     return item.ToString(); 
    } 
} 

KeyedCollection<string, int> intCollection = new ClassThatContainsSealedImplementation.IntDictionary(); 

intCollection.Add(7); 

int valueByIndex = intCollection[0]; 
2

要扩大丹尼尔斯后和他有关的关键意见,因为密钥嵌入值的范围内,无论如何,你可以求助于使用KeyValuePair<TKey, TValue>作为值。主要原因是,一般来说,密钥不一定可以直接从值中导出。

然后它会是这样的:

public sealed class CustomDictionary<TKey, TValue> 
    : KeyedCollection<TKey, KeyValuePair<TKey, TValue>> 
{ 
    protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item) 
    { 
    return item.Key; 
    } 
} 

以此作为在前面的例子,你会怎么做:

CustomDictionary<string, int> custDict = new CustomDictionary<string, int>(); 

custDict.Add(new KeyValuePair<string, int>("key", 7)); 

int valueByIndex = custDict[0].Value; 
int valueByKey = custDict["key"].Value; 
string keyByIndex = custDict[0].Key; 
2

您还可以使用排序列表及其对应的通用。这两个类在Andrew Peters的答案中提到的OrderedDictionary是字典类,其中的项目可以通过索引(位置)以及按键来访问。如何使用这些类可以找到:SortedList ClassSortedList Generic Class

2

字典可能不适合使用指数作为参考很直观,但是,你可以有类似的操作与KeyValuePair数组:

前。 KeyValuePair<string, string>[] filters;

1

Visual Studio的UserVoice给出了dotmore的generic OrderedDictionary implementation的链接。

但是如果你只需要通过索引来获取键/值对,不需要通过键获取值,你可以使用一个简单的一招。声明一些通用类(我把它叫做ListArray)如下:

class ListArray<T> : List<T[]> { } 

你也可以用构造函数声明它:

class ListArray<T> : List<T[]> 
{ 
    public ListArray() : base() { } 
    public ListArray(int capacity) : base(capacity) { } 
} 

例如,从文件中读取一些键/值对,只是想将它们存储在他们看了这么被索引后得到的顺序排列:

ListArray<string> settingsRead = new ListArray<string>(); 
using (var sr = new StreamReader(myFile)) 
{ 
    string line; 
    while ((line = sr.ReadLine()) != null) 
    { 
     string[] keyValueStrings = line.Split(separator); 
     for (int i = 0; i < keyValueStrings.Length; i++) 
      keyValueStrings[i] = keyValueStrings[i].Trim(); 
     settingsRead.Add(keyValueStrings); 
    } 
} 
// Later you get your key/value strings simply by index 
string[] myKeyValueStrings = settingsRead[index]; 

正如你可能已经注意到,你可以不一定只是对键/值对您的ListArray。项目数组可以是任何长度,如锯齿状阵列。

相关问题