其中.NET集合更快:枚举的foreach字典<> .Values​​或列表<>? [英] Which .NET collection is faster: enumerating foreach Dictionary<>.Values or List<>?

查看:115
本文介绍了其中.NET集合更快:枚举的foreach字典<> .Values​​或列表<>?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

难道这些枚举之一比其他或差不多快? (例如C#)

案例1:

 词典<字符串,对象> values​​Dict;

// values​​Dict装有成千上万个对象

的foreach(在values​​Dict.Values​​对象的值){/ *进程* /}
 

案例2:

 名单,其中,对象> Values​​List中;

// Values​​List中装有成千上万个对象

的foreach(在Values​​List中对象的值){/ *进程* /}
 

更新:

背景:

的字典将是有益的别处键控搜索(而不是通过迭代列表),但是,如果通过字典迭代是不是通过列表慢得多的好处将被削弱。

更新: 采取了许多的意见,我已经做了我自己的测试。

首先,这些是结果。以下是该程序

迭代整个集合 快译通:78 Keyd:131 列表:76

键控搜索集合 快译通:178 Keyd:194 清单:142800

 使用系统;
使用System.Linq的;

命名空间IterateCollections
{
    公共类数据
    {
        公共字符串ID;
        公共字符串文本;
    }

    公共类KeyedData:System.Collections.ObjectModel.KeyedCollection<字符串,数据和GT;
    {
        保护覆盖字符串GetKeyForItem(数据项)
        {
            返回item.Id;
        }
    }

    类节目
    {
        静态无效的主要(字串[] args)
        {
            VAR字典=新System.Collections.Generic.Dictionary<字符串,数据及GT;();
            VAR名单=新System.Collections.Generic.List<数据>();
            VAR keyd =新KeyedData();

            的for(int i = 0; I< 10000;我++)
            {
                字符串s = i.ToString();
                变种D =新的数据{n = S,文本= S};
                dict.Add(d.Id,D);
                list.Add(四);
                keyd.Add(四);
            }

            变种SW =新System.Diagnostics.Stopwatch();
            sw.Start();
            对于(INT R = 0; R< 1000; R ++)
            {
                的foreach(在dict.Values​​数据D)
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            VAR dictTime = sw.ElapsedMilliseconds;

            sw.Reset();
            sw.Start();
            对于(INT R = 0; R< 1000; R ++)
            {
                的foreach(在keyd数据D)
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            VAR keydTime = sw.ElapsedMilliseconds;

            sw.Reset();
            sw.Start();
            对于(INT R = 0; R< 1000; R ++)
            {
                的foreach(列表中的数据D)
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            VAR listTime = sw.ElapsedMilliseconds;

            Console.WriteLine(遍历整个集合);
            Console.WriteLine(字典+ dictTime);
            Console.WriteLine(Keyd:+ keydTime);
            Console.WriteLine(名单:+ listTime);

            sw.Reset();
            sw.Start();
            对于(INT R = 0; R< 1000; R ++)
            {
                的for(int i = 0; I< 10000; I + = 10)
                {
                    字符串s = i.ToString();
                    数据D =字典[S]。
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            dictTime = sw.ElapsedMilliseconds;

            sw.Reset();
            sw.Start();
            对于(INT R = 0; R< 1000; R ++)
            {
                的for(int i = 0; I< 10000; I + = 10)
                {
                    字符串s = i.ToString();
                    数据D = keyd [S]。
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            keydTime = sw.ElapsedMilliseconds;

            sw.Reset();
            sw.Start();
            对(INT R = 0;为r 10; R ++)
            {
                的for(int i = 0; I< 10000; I + = 10)
                {
                    字符串s = i.ToString();
                    数据D = list.FirstOrDefault(项目=> item.Id == S);
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            listTime = sw.ElapsedMilliseconds * 100;

            Console.WriteLine(键控搜索集合);
            Console.WriteLine(字典+ dictTime);
            Console.WriteLine(Keyd:+ keydTime);
            Console.WriteLine(名单:+ listTime);

        }
    }
 

}

更新:

字典与KeyedCollection比较所建议的@Blam。

最快的方法是遍历KeyedCollection项目的数组。

请注意,但是,遍历字典值比在KeyedCollection快,无需转换到一个数组中。

需要注意的是遍历字典中的值是多少,比在字典集合快多了。

 迭代1000次以上收集10000项
   词典对:519毫秒
 字典值:95毫秒
  快译通瓦尔的ToArray:92毫秒
   KeyedCollection:141毫秒
   KeyedC。的ToArray:17毫秒
 

计时是从Windows控制台应用程序(发布版本)。这里是源$ C ​​$ C:

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;

命名空间IterateCollections
{
    公共类GUIDkeyCollection:System.Collections.ObjectModel.KeyedCollection< GUID,可GUIDkey>
    {
        //这个参数的构造函数调用基类的构造函数
        //指定为0的字典的阈值,使内部
        //字典是只要一个项目被添加到所创建的
        // 采集。
        //
        公共GUIDkeyCollection():碱(){}

        //这是绝对必须重写的唯一方法,
        //因为没有它的KeyedCollection不能提取
        //从项目的键。
        //
        保护覆盖的Guid GetKeyForItem(GUIDkey项)
        {
            //在这个例子中,关键是部件号。
            返回item.Key;
        }

        公共GUIDkey []的ToArray()
        {
            返回Items.ToArray();
        }

        // [过时(迭代使用.ToArray(),真)
        //市民新的IEnumerator的GetEnumerator()
        // {
        //抛出新的NotImplementedException(迭代使用.ToArray());
        //}
    }
    公共类GUIDkey:对象
    {
        私人GUID项;
        公共GUID项
        {
            得到
            {
                返回键;
            }
        }
        公众覆盖布尔等于(obj对象)
        {
            //检查是否为空,并比较运行时类型。
            如果(!OBJ == NULL ||(obj为GUIDkey))返回false;
            GUIDkey项目=(GUIDkey)目标文件;
            返程(关键== item.Key);
        }
        公众覆盖INT GetHash code(){返回Key.GetHash code(); }
        公共GUIDkey(GUID GUID)
        {
            键= GUID;
        }
    }

    类节目
    {
        静态无效的主要(字串[] args)
        {
            const int的ItemCount中= 10000;
            const int的重复= 1000;
            常量字符串的resultFormat ={0,18} {1,5:D}毫秒;

            Console.WriteLine(迭代{0:N0}次以上集合{1:N0}项目,重复,ItemCount中);

            VAR字典=新字典< GUID,可GUIDkey>();
            VAR keyd =新GUIDkeyCollection();

            的for(int i = 0; I< ItemCount中,我++)
            {
                变种D =新GUIDkey(Guid.NewGuid());
                dict.Add(d.Key,D);
                keyd.Add(四);
            }

            变种SW =新System.Diagnostics.Stopwatch();
            很长时间;

            sw.Reset();
            sw.Start();
            对于(INT R = 0;为r重复; R ++)
            {
                的foreach(KeyValuePair< GUID,可GUIDkey>中W字典)
                {
                    如果(空== w.Value)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            时间= sw.ElapsedMilliseconds;
            Console.WriteLine(的resultFormat,字典对,时间);

            sw.Reset();
            sw.Start();
            对于(INT R = 0;为r重复; R ++)
            {
                的foreach(GUIDkey d在dict.Values​​)
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            时间= sw.ElapsedMilliseconds;
            Console.WriteLine(的resultFormat,字典值,时间);

            sw.Reset();
            sw.Start();
            对于(INT R = 0;为r重复; R ++)
            {
                的foreach(在dict.Values​​.ToArray GUIDkey D())
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            时间= sw.ElapsedMilliseconds;
            Console.WriteLine(的resultFormat,快译通瓦尔的ToArray,时间);

            sw.Reset();
            sw.Start();
            对于(INT R = 0;为r重复; R ++)
            {
                的foreach(GUIDkey d在keyd)
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            时间= sw.ElapsedMilliseconds;
            Console.WriteLine(的resultFormat,KeyedCollection,时间);

            sw.Reset();
            sw.Start();
            对于(INT R = 0;为r重复; R ++)
            {
                的foreach(在keyd.ToArray GUIDkey D())
                {
                    如果(空== D)抛出新ApplicationException的();
                }
            }
            sw.Stop();
            时间= sw.ElapsedMilliseconds;
            Console.WriteLine(的resultFormat,KeyedC的ToArray,时间);
        }
    }

}
 

解决方案

这是比较容易检查用秒表:

 变种D =新字典<字符串,对象>();
变种S =新名单,其中,对象>();
的for(int i = 0; i =千万;!我++){
    d.Add(+ I,I);
    s.Add(ⅰ);
}
变种SW =新的秒表();
sw.Start();
的foreach(在d.Values​​对象o){
    如果(O == NULL)抛出新ApplicationException的();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
的foreach(以秒对象o){
    如果(O == NULL)抛出新ApplicationException的();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
 

这版画是相当接近对方号码:

 词典列表
---- ----
 136 107
 139 108
 136 108
 

列表总是获胜,但利润并不大如人们所期望的,因为这两个数据结构的相对复杂性。

Are one of these enumerations faster than the other or about the same? (example in C#)

Case 1:

Dictionary<string, object> valuesDict;

// valuesDict loaded with thousands of objects

foreach (object value in valuesDict.Values) { /* process */ }

Case 2:

List<object> valuesList;

// valuesList loaded with thousands of objects

foreach (object value in valuesList) { /* process */ }

UPDATE:

Background:

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.

UPDATE: Taking the advice of many, I've done my own testing.

First, these are the results. Following is the program.

Iterate whole collection Dict: 78 Keyd: 131 List: 76

Keyed search collection Dict: 178 Keyd: 194 List: 142800

using System;
using System.Linq;

namespace IterateCollections
{
    public class Data
    {
        public string Id;
        public string Text;
    }

    public class KeyedData : System.Collections.ObjectModel.KeyedCollection<string, Data>
    {
        protected override string GetKeyForItem(Data item)
        {
            return item.Id;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var dict = new System.Collections.Generic.Dictionary<string, Data>();
            var list = new System.Collections.Generic.List<Data>();
            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 < 10000; i += 10)
                {
                    string s = i.ToString();
                    Data d = list.FirstOrDefault(item => 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);

        }
    }

}

UPDATE:

Comparison of Dictionary with KeyedCollection as suggested by @Blam.

The fastest method is iterating over an Array of KeyedCollection Items.

Note, however, that iterating over the dictionary values is faster than over the KeyedCollection without converting to an array.

Note that iterating over the dictionary values is much, much faster than over the dictionary collection.

 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

Timings are from a Windows console application (Release build). Here is the source code:

using System;
using System.Collections.Generic;
using System.Linq;

namespace IterateCollections
{
    public class GUIDkeyCollection : System.Collections.ObjectModel.KeyedCollection<Guid, GUIDkey>
    {
        // 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<Guid, GUIDkey>();
            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<Guid, GUIDkey> 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);
        }
    }

}

解决方案

This is relatively easy to check with a stopwatch:

var d = new Dictionary<string, object>();
var s = new List<object>();
for (int i =0 ; i != 10000000 ; i++) {
    d.Add(""+i, i);
    s.Add(i);
}
var sw = new Stopwatch();
sw.Start();
foreach(object o in d.Values) {
    if (o == null) throw new ApplicationException();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
foreach (object o in s) {
    if (o == null) throw new ApplicationException();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

This prints numbers that are reasonably close to each other:

Dict List
---- ----
 136  107
 139  108
 136  108

The List always wins, but the margins are not as large as one would expect, given the relative complexity of the two data structures.

这篇关于其中.NET集合更快:枚举的foreach字典&LT;&GT; .Values​​或列表&LT;&GT;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆