2011-04-14 47 views
2

我有一個Dictionary<int, int>和想更新某些元件一次全部基於它們的電流值,例如將值爲10的所有元素更改爲具有值14或其他值。快速大規模更新字典

我想象這會很容易與一些LINQ /λ的東西,但它似乎並不像我想的那麼簡單。我目前的做法是這樣的:(幾百元的千),我跑在一個循環數千次這樣的代碼,因此它是令人難以置信的慢

List<KeyValuePair<int, int>> kvps = dictionary.Where(d => d.Value == oldValue).ToList(); 
foreach (KeyValuePair<int, int> kvp in kvps) 
{ 
    dictionary[KeyValuePair.Key] = newValue; 
} 

的問題是,dictionary是相當大的。必須有一個更好的辦法...

+0

@Paulo - 沒有,很遺憾。 – 2011-04-14 19:21:22

+0

如果您生成新的字典,該怎麼辦? – JonH 2011-04-14 19:21:49

+0

@JonH:那會更慢。 – recursive 2011-04-14 19:45:38

回答

6

這可能是錯誤的數據結構。您正試圖根據它們的值查找字典條目,這與通常的模式相反。也許你可以存儲當前映射到特定值的鍵集。然後,您可以快速移動這些設置,而不是單獨更新每個條目。

+0

這更像它。 – 2011-04-14 19:28:57

+0

然後,通過鍵可以查找更慢,不是嗎? – 2011-04-14 19:31:46

+0

我認爲這是我的原創方法,但是效果不好,可能是因爲我使用的算法,所以我會再試一次。 – 2011-04-14 19:32:30

0

你需要生成一個新的字典:

d = d.ToDictionary(w => w.Key, w => w.Value == 10 ? 14 : w.Value)

+2

好主意;不幸的是,它似乎運行得更慢。 – 2011-04-14 19:23:38

+0

@Andrew Arnold--記得它是一個lambda :),你的for循環可能是我能想到的唯一選擇,用於快速和骯髒。或者考慮@Jeff Yates的建議。 – JonH 2011-04-14 19:24:13

+2

它不能解決O.P.所存在的問題,因爲在引導下,字典將循環遍歷元素,並逐個將鍵值對添加到新對象。 – 2011-04-14 19:25:46

2

我會考慮寫自己的集合類型實現了與相同的值,從而這實際上鍵分享相同的值實例,以便在一個位置更改它可以更改所有密鑰。

類似下面的(顯然,大量的代碼在這裏省略 - 只是用於說明目的):

public class SharedValueDictionary : IDictionary<int, int> 
{ 
    private List<MyValueObject> values; 

    private Dictionary<int, MyValueObject> keys; 

    // Now, when you add a new key/value pair, you actually 
    // look in the values collection to see if that value already 
    // exists. If it does, you add an entry to keys that points to that existing object 
    // otherwise you create a new MyValueObject to wrap the value and add entries to 
    // both collections. 
} 

這種情況將需要AddRemove多個版本,以允許改變所有的鍵具有相同的值,只更改一個集合中的一個鍵爲新值,刪除所有具有相同值的鍵並從值集中移除一個鍵。在需要時編寫這些場景並不困難。

+0

這種方法的問題是如果一個鍵值對需要更新並且另一個具有相同值的對不對? – 2011-04-14 19:24:15

+0

@Paulo Santos - 如果其中一個改變了,另一個會自動改變。 – JonH 2011-04-14 19:25:35

+1

我明白Jeff提出的方法,但問題依然存在。想象一下,例如,我們有一對X:10和Y:10,X需要更新到15,但不是Y.傑夫建議的集合會將X和Y都更改爲相同的值,總是。 – 2011-04-14 19:27:51

0

我認爲每個人都必須缺少的東西是,它是exceeeeedingly簡單:

List<int> keys = dictionary.Keys.Where(d => d == oldValue); 

您是查找按值鍵(如已被他人提供)。 相反,keys.SingleOrDefault()將現在定義返回是否在字典中存在等於oldValue單鍵。所以整個代碼應該簡化爲

if (dictionary.ContainsKey(oldValue)) 
    dictionary[key] = newValue; 

這很快。現在我有點擔心這可能確實是OP何意,但它他寫的東西。因此,如果現有的代碼做他需要的東西,他會現在有同樣的:)

+0

不,實際上; 'ContainsKey'將查找字典中*鍵*爲'oldValue'的所有元素;我想要* value *爲'oldValue'的元素。 – 2011-04-14 20:09:56

+0

是的,我很確定我的代碼在這個問題中並沒有真正反映我的意思。 – 2011-04-14 20:11:11

+0

我已經做了編輯。 – 2011-04-14 20:26:36

0

編輯後一套高性能的版本,這似乎立即得到改善:

foreach (var kvp in dictionary.Where(d => d.Value == oldValue)) 
{ 
    kvp.Value = newValue; 
} 

我敢肯定你可以直接更新KVP,只要關鍵是不能改變

+0

我已經試過這個,你不能這樣做。 「Value」屬性是隻讀的。改變它的唯一方法是通過關鍵。 – 2011-04-14 20:32:03

+0

正確的我剛剛發現通過試圖讓這個在探查器:) – sehe 2011-04-14 20:36:29