title: Which .NET collection is faster: enumerating foreach Dictionary<>.Values or List<>?
body: <p>Are one of these enumerations faster than the other or about the same? (example in C#)</p>
  
  <p>Case 1:</p>
  
  <pre><code>Dictionary&lt;string, object&gt; valuesDict;
  
  // valuesDict loaded with thousands of objects
  
  foreach (object value in valuesDict.Values) { /* process */ }
  </code></pre>
  
  <p>Case 2:</p>
  
  <pre><code>List&lt;object&gt; valuesList;
  
  // valuesList loaded with thousands of objects
  
  foreach (object value in valuesList) { /* process */ }
  </code></pre>
  
  <p>UPDATE:</p>
  
  <p>Background:</p>
  
  <p>The dictionary would be beneficial for keyed search elsewhere (as opposed to iterating through a list), but the benefit would be diminished if iterating through the dictionary is much slower than going through the list.</p>
  
  <p>UPDATE:
  Taking the advice of many, I've done my own testing.</p>
  
  <p>First, these are the results. Following is the program.</p>
  
  <p>Iterate whole collection
  Dict: 78
  Keyd: 131
  List: 76</p>
  
  <p>Keyed search collection
  Dict: 178
  Keyd: 194
  List: 142800</p>
  
  <pre><code>using System;
  using System.Linq;
  
  namespace IterateCollections
  {
      public class Data
      {
          public string Id;
          public string Text;
      }
  
      public class KeyedData : System.Collections.ObjectModel.KeyedCollection&lt;string, Data&gt;
      {
          protected override string GetKeyForItem(Data item)
          {
              return item.Id;
          }
      }
  
      class Program
      {
          static void Main(string[] args)
          {
              var dict = new System.Collections.Generic.Dictionary&lt;string, Data&gt;();
              var list = new System.Collections.Generic.List&lt;Data&gt;();
              var keyd = new KeyedData();
  
              for (int i = 0; i &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 1000; r++)
              {
                  for (int i = 0; i &lt; 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 &lt; 1000; r++)
              {
                  for (int i = 0; i &lt; 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 &lt; 10; r++)
              {
                  for (int i = 0; i &lt; 10000; i += 10)
                  {
                      string s = i.ToString();
                      Data d = list.FirstOrDefault(item =&gt; 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);
  
          }
      }
  </code></pre>
  
  <p>}</p>
  
  <p>UPDATE:</p>
  
  <p>Comparison of Dictionary with KeyedCollection as suggested by @Blam.</p>
  
  <p>The fastest method is iterating over an Array of KeyedCollection Items.</p>
  
  <p>Note, however, that iterating over the dictionary values is faster than over the KeyedCollection without converting to an array.</p>
  
  <p>Note that iterating over the dictionary values is much, much faster than over the dictionary collection.</p>
  
  <pre><code> 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
  </code></pre>
  
  <p>Timings are from a Windows console application (Release build). Here is the source code:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace IterateCollections
  {
      public class GUIDkeyCollection : System.Collections.ObjectModel.KeyedCollection&lt;Guid, GUIDkey&gt;
      {
          // 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&lt;Guid, GUIDkey&gt;();
              var keyd = new GUIDkeyCollection();
  
              for (int i = 0; i &lt; 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 &lt; repetitions; r++)
              {
                  foreach (KeyValuePair&lt;Guid, GUIDkey&gt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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);
          }
      }
  
  }
  </code></pre>