2008-08-07 105 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。項目數組可以是任何長度,如鋸齒狀陣列。

相關問題