using System; using System.Linq; namespace IterateCollections { public class Data { public string Id; public string Text; } public class KeyedData : System.Collections.ObjectModel.KeyedCollection { protected override string GetKeyForItem(Data item) { return item.Id; } } class Program { static void Main(string[] args) { var dict = new System.Collections.Generic.Dictionary(); var list = new System.Collections.Generic.List(); var keyd = new KeyedData(); for (int i = 0; i < 10000; i++) { string s = i.ToString(); var d = new Data { Id = s, Text = s }; dict.Add(d.Id, d); list.Add(d); keyd.Add(d); } var sw = new System.Diagnostics.Stopwatch(); sw.Start(); for (int r = 0; r < 1000; r++) { foreach (Data d in dict.Values) { if (null == d) throw new ApplicationException(); } } sw.Stop(); var dictTime = sw.ElapsedMilliseconds; sw.Reset(); sw.Start(); for (int r = 0; r < 1000; r++) { foreach (Data d in keyd) { if (null == d) throw new ApplicationException(); } } sw.Stop(); var keydTime = sw.ElapsedMilliseconds; sw.Reset(); sw.Start(); for (int r = 0; r < 1000; r++) { foreach (Data d in list) { if (null == d) throw new ApplicationException(); } } sw.Stop(); var listTime = sw.ElapsedMilliseconds; Console.WriteLine("Iterate whole collection"); Console.WriteLine("Dict: " + dictTime); Console.WriteLine("Keyd: " + keydTime); Console.WriteLine("List: " + listTime); sw.Reset(); sw.Start(); for (int r = 0; r < 1000; r++) { for (int i = 0; i < 10000; i += 10) { string s = i.ToString(); Data d = dict[s]; if (null == d) throw new ApplicationException(); } } sw.Stop(); dictTime = sw.ElapsedMilliseconds; sw.Reset(); sw.Start(); for (int r = 0; r < 1000; r++) { for (int i = 0; i < 10000; i += 10) { string s = i.ToString(); Data d = keyd[s]; if (null == d) throw new ApplicationException(); } } sw.Stop(); keydTime = sw.ElapsedMilliseconds; sw.Reset(); sw.Start(); for (int r = 0; r < 10; r++) { for (int i = 0; i item.Id == s); if (null == d) throw new ApplicationException(); } } sw.Stop(); listTime = sw.ElapsedMilliseconds * 100; Console.WriteLine("Keyed search collection"); Console.WriteLine("Dict: " + dictTime); Console.WriteLine("Keyd: " + keydTime); Console.WriteLine("List: " + listTime); } }
}
更新:
@Blam建议的字典与KeyedCollection的比较。
最快的方法是迭代KeyedCollection项目数组。
但请注意,迭代字典值比KeyedCollection快,而不转换为数组。
请注意,迭代字典值比字典集合快得多。
Iterate 1,000 times over collection of 10,000 items Dictionary Pair: 519 ms Dictionary Values: 95 ms Dict Val ToArray: 92 ms KeyedCollection: 141 ms KeyedC. ToArray: 17 ms
计时来自Windows控制台应用程序(发布版本)。 这是源代码:
using System; using System.Collections.Generic; using System.Linq; namespace IterateCollections { public class GUIDkeyCollection : System.Collections.ObjectModel.KeyedCollection { // This parameterless constructor calls the base class constructor // that specifies a dictionary threshold of 0, so that the internal // dictionary is created as soon as an item is added to the // collection. // public GUIDkeyCollection() : base() { } // This is the only method that absolutely must be overridden, // because without it the KeyedCollection cannot extract the // keys from the items. // protected override Guid GetKeyForItem(GUIDkey item) { // In this example, the key is the part number. return item.Key; } public GUIDkey[] ToArray() { return Items.ToArray(); } //[Obsolete("Iterate using .ToArray()", true)] //public new IEnumerator GetEnumerator() //{ // throw new NotImplementedException("Iterate using .ToArray()"); //} } public class GUIDkey : Object { private Guid key; public Guid Key { get { return key; } } public override bool Equals(Object obj) { //Check for null and compare run-time types. if (obj == null || !(obj is GUIDkey)) return false; GUIDkey item = (GUIDkey)obj; return (Key == item.Key); } public override int GetHashCode() { return Key.GetHashCode(); } public GUIDkey(Guid guid) { key = guid; } } class Program { static void Main(string[] args) { const int itemCount = 10000; const int repetitions = 1000; const string resultFormat = "{0,18}: {1,5:D} ms"; Console.WriteLine("Iterate {0:N0} times over collection of {1:N0} items", repetitions, itemCount); var dict = new Dictionary(); var keyd = new GUIDkeyCollection(); for (int i = 0; i < itemCount; i++) { var d = new GUIDkey(Guid.NewGuid()); dict.Add(d.Key, d); keyd.Add(d); } var sw = new System.Diagnostics.Stopwatch(); long time; sw.Reset(); sw.Start(); for (int r = 0; r < repetitions; r++) { foreach (KeyValuePair w in dict) { if (null == w.Value) throw new ApplicationException(); } } sw.Stop(); time = sw.ElapsedMilliseconds; Console.WriteLine(resultFormat, "Dictionary Pair", time); sw.Reset(); sw.Start(); for (int r = 0; r < repetitions; r++) { foreach (GUIDkey d in dict.Values) { if (null == d) throw new ApplicationException(); } } sw.Stop(); time = sw.ElapsedMilliseconds; Console.WriteLine(resultFormat, "Dictionary Values", time); sw.Reset(); sw.Start(); for (int r = 0; r < repetitions; r++) { foreach (GUIDkey d in dict.Values.ToArray()) { if (null == d) throw new ApplicationException(); } } sw.Stop(); time = sw.ElapsedMilliseconds; Console.WriteLine(resultFormat, "Dict Val ToArray", time); sw.Reset(); sw.Start(); for (int r = 0; r < repetitions; r++) { foreach (GUIDkey d in keyd) { if (null == d) throw new ApplicationException(); } } sw.Stop(); time = sw.ElapsedMilliseconds; Console.WriteLine(resultFormat, "KeyedCollection", time); sw.Reset(); sw.Start(); for (int r = 0; r < repetitions; r++) { foreach (GUIDkey d in keyd.ToArray()) { if (null == d) throw new ApplicationException(); } } sw.Stop(); time = sw.ElapsedMilliseconds; Console.WriteLine(resultFormat, "KeyedC. ToArray", time); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.ObjectModel; using System.Diagnostics; namespace IntIntKeyedCollection { class Program { static void Main(string[] args) { Guid findGUID = Guid.NewGuid(); GUIDkeyCollection gUIDkeyCollection = new GUIDkeyCollection(); gUIDkeyCollection.Add(new GUIDkey(findGUID)); gUIDkeyCollection.Add(new GUIDkey(Guid.NewGuid())); gUIDkeyCollection.Add(new GUIDkey(Guid.NewGuid())); GUIDkey findGUIDkey = gUIDkeyCollection[findGUID]; // lookup by key (behaves like a dict) Console.WriteLine(findGUIDkey.Key); Console.WriteLine(findGUIDkey.GetHashCode()); Console.WriteLine(findGUID); Console.WriteLine(findGUID.GetHashCode()); Console.ReadLine(); } public class GUIDkeyCollection : KeyedCollection { // This parameterless constructor calls the base class constructor // that specifies a dictionary threshold of 0, so that the internal // dictionary is created as soon as an item is added to the // collection. // public GUIDkeyCollection() : base() { } // This is the only method that absolutely must be overridden, // because without it the KeyedCollection cannot extract the // keys from the items. // protected override Guid GetKeyForItem(GUIDkey item) { // In this example, the key is the part number. return item.Key; } } public class GUIDkey : Object { private Guid key; public Guid Key { get { return key; } } public override bool Equals(Object obj) { //Check for null and compare run-time types. if (obj == null || !(obj is GUIDkey)) return false; GUIDkey item = (GUIDkey)obj; return (Key == item.Key); } public override int GetHashCode() { return Key.GetHashCode(); } public GUIDkey(Guid guid) { key = guid; } } } }
这是你的测试:
class speedtest { static void Main(string[] args) { int size = 10000000; Dictionary valuesDict = new Dictionary(); List
void Main() { int i = 0; var dict = new Dictionary(); var list = new List(); for (i = 0; i < 30000; i++) { var foo = new Foo(); dict.Add(i.ToString(), foo); list.Add(foo); } var dictWatch = new Stopwatch(); dictWatch.Start(); for (i = 0; i < 10000; i++) { foreach (var foo in dict.Values) {} } dictWatch.Stop(); Console.WriteLine("Dictionary: " + dictWatch.ElapsedMilliseconds); var listWatch = new Stopwatch(); listWatch.Start(); for (i = 0; i < 10000; i++) { foreach (var foo in list) {} } listWatch.Stop(); Console.WriteLine("List: " + listWatch.ElapsedMilliseconds); } class Foo {}