2014-09-11 89 views
1

我有以下ConcurrentDictionary.Where基於過濾int數組(鍵字段)

var links = new ConcurrentDictionary<int, Link>(); 

其中填充有20K左右的記錄速度很慢,我有一個字符串(列表)的另一個數組,我變成INT使用以下數組。

var intPossible = NonExistingListingIDs.Select(int.Parse); //this is very fast but need to be done 

這很快。但我想創建一個新的列表或者僅僅過濾出與「ConcurrentDictionary」的Key元素相匹配的intPossible數組中的「鏈接」。

我有以下使用where子句,但它需要大約50秒做實際的過濾,這是我想要做的非常慢。

var filtered = links.Where(x => intPossible.Any(y => y == x.Key)).ToList(); 

我知道相交是相當快的,但我有INTS的陣列和Intersect是不是跟這個工作對一個ConcurrentDictionary

如何過濾的鏈接,會快一點,而不是50秒。

回答

3

你需要用一個更快的東西來代替你的O(n)內部查找,就像一個爲查找提供O(1)複雜性的哈希集合。

所以

var intPossible = new HashSet<int>(NonExistingListingIDs.Select(int.Parse)); 

var filtered = links.Where(x => intPossible.Contains(x.Key)).ToList(); 

這將避免在links迭代大部分intPossible爲每個項目。

另外,LINQ的是你的朋友:

var intPossible = NonExistingListingIDs.Select(int.Parse); 
var filtered = 
    links.Join(intPossible, link => link.Key, intP => intP, (link, intP) => link); 

的實現加入做同樣的事情,因爲我上面做的。

+1

第一個版本運行良好,現在以毫秒爲單位。謝謝,等着將它標記爲答案。 – Zoinky 2014-09-11 01:16:08

+0

@Zoinky,是的......我預料如此。這個問題可能是因爲你的'intPossible'實際上不是一個數組,而是一個非實體化的IEnumerable。每次您通過調用'.Any'來迭代它時,都必須重新分析NonExistingListingID中的字符串,這會增加操作的負擔。通過將它放入HashSet中,它只會枚舉一次(但自然需要更多的內存來存儲)。 – spender 2014-09-11 01:20:20

1

的另一種方法是枚舉列表,並使用詞典的索引...可能有點清潔...

var intPossible = NonExistingListingIDs.Select(int.Parse); 
var filtered = from id in intPossible 
       where links.ContainsKey(id) 
       select links[id]; 

你可能想在認輸的.ToList()那裏好測量太...

這實際上應該比@ spender的解決方案稍快,因爲.Join必須創建一個新的HashTable,而此方法使用ConcurrentDictionary中的HashTable。