2008-09-30 113 views
22

我剛剛看到這種行爲,我有點驚訝它...爲什麼在.Net詞典中添加了條目?

如果我添加3或4個元素到一個字典,然後做一個「For Each」來獲得所有的鍵,它們出現按照相同的順序,我添加了它們。

的原因,這讓我驚訝的是,字典應該是內部哈希表,所以我預期的事情在任何順序出來(由密鑰的散列有序的,對吧?)

我是什麼在這裏失蹤? 這是我能指望的行爲嗎?

編輯:好的,我認爲已經有很多原因可能會發生這種(如單獨的列表到條目,這是否是巧合等)。 我的問題是,有沒有人知道這是如何工作的?

回答

38

如果在3.5類庫上使用.NET Reflector,則可以看到Dictionary的實現實際上將項目存儲在數組中(根據需要調整大小),並將索引散列到該數組中。獲取密鑰時,它會完全忽略散列表並遍歷項目數組。出於這個原因,您將看到自從在數組末尾添加新項目之後所描述的行爲。看起來,如果你做如下所示:

add 1 
add 2 
add 3 
add 4 
remove 2 
add 5 

你會得到1 5 3 4,因爲它重用空插槽。

重要的是要注意,像許多其他人一樣,在未來(或過去)版本中,您不能指望此行爲。如果你想要你的字典排序,那麼這個類有一個SortedDictionary類。

8

字典以散列順序檢索項目。他們以插入順序出來的事實完全是巧合。

MSDN文檔說:

在KeyCollection按鍵的順序是不確定的,但它是相同的順序,由值屬性返回的ValueCollection關聯的值。

+0

好吧,不是*總數*巧合。通過一個小樣本,我發現它們通常按照與添加它們相同的順序出現。仍然,很好的答案! – Danimal 2008-09-30 18:28:13

+0

我不認爲這是巧合。我確實改變了添加相同元素的順序,看看它是否會改變。所以這不是什麼情況。如果我獲得足夠多的數據,.Net可能會做得不同。 – 2008-09-30 18:57:34

+0

如果你閱讀文檔,這仍然是你不應該指望的巧合。即使您深入瞭解代碼,以瞭解爲什麼它爲少量的密鑰做這件事,#可能會改變,或者它可能永遠不會在舊版/新版框架版本中成爲現實。 – 2008-10-01 05:25:41

0

從我所知道的這不應該是一個依賴的行爲。要快速檢查它,請使用相同的元素並更改將它們添加到字典中的順序。你會看到你是否按照他們添加的順序將它們還原,或者這只是一個巧合。

+0

我明顯這樣做:-)我得到他們在我添加它們的相同順序,這不是巧合 – 2008-09-30 18:56:34

1

MSDN引述:

的鍵的在 字典<的順序(<(TKEY的, TValue>中)>)KeyCollection是 未指定的,但它是相同的順序 。如在 字典<相關值(<(TKEY的, TValue>中)>)。ValueCollection 由詞典<返回(中<(TKEY的, TValue>中)>)。Va的提供財產。

1

你在測試中添加了什麼鍵,以什麼順序?

5

你不能指望這種行爲,但這並不奇怪。

考慮如何實現簡單哈希表的密鑰迭代。你需要迭代所有的哈希桶,不管它們中是否有任何內容。從大散列表中獲取小數據集可能效率低下。

因此,它可能是一個很好的優化,保持一個單獨的,重複的密鑰列表。使用雙鏈表,您仍然可以進行常量插入/刪除。 (您可以將散列表存儲區的指針保留回這個列表中。)這樣,遍歷鍵列表只會取決於條目的數量,而不取決於存儲區的數量。

2

我認爲這來自舊的.NET 1.1時代,你有兩種字典「ListDictionary」和「HybridDictionary」。 ListDictionary是內部作爲有序列表實施的字典,並被推薦用於「小組條目」。然後你有HybridDictionary,它最初是作爲一個列表在內部組織的,但是如果它長於一個可配置的閾值就會成爲一個哈希表。這是因爲歷史上適當的基於散列的字典被認爲是昂貴的。現在有一天沒有什麼意義,但我想.NET只是基於舊的HybridDictionary上的新的Dictionary通用類。

注意:不管怎麼說,正如有人已經指出的那樣,你應該從未計數字典順序上的任何東西

1

你的項目可能全部是在字典中的一個桶。每個存儲桶可能都是存儲桶中的條目列表。這將解釋條目回來的順序。

0

到一定的列表大小時,只檢查每個條目而不是散列就會更便宜。這可能是正在發生的事情。

添加100個或1000個項目,看看它們是否仍然是相同的順序。

+0

3.5實現將枚舉它們爲了任何數量的元素(請查看我的答案以獲取更多詳細信息)。 – Dolphin 2009-06-10 16:56:09

-1

這個問題和許多答案似乎誤解了散列表或字典的目的。這些數據結構在數據結構中包含的項的值(或實際上的鍵)枚舉方面沒有規定的行爲。

字典或散列表的目的是爲了能夠有效地查找給定已知密鑰的特定值。任何字典或散列表的內部實現應該在查找時提供這種效率,但不需要針對枚舉或「對於每個」值或鍵上的類型迭代提供任何特定行爲。

簡而言之,內部數據結構可以按照它希望的任何方式存儲和枚舉這些值,包括它們被插入的順序。

0

我討厭這種「按設計」功能。我認爲,當給你的班級一個如「字典」這樣的通用名稱時,它也應該「按照通常的預期」行事。例如,std :: map總是保持它的鍵值排序。

編輯:顯然,解決方案是使用SortedDictionary,其行爲與std :: map類似。

相關問題