c标签foreach遍历list_遍历 Dictionary,你会几种方式?

一:背景

1. 讲故事

昨天在 StackOverflow 上看到一个很有趣的问题,说: 你会几种遍历字典的方式,然后跟帖就是各种奇葩的回答,挺有意思,马上就要国庆了,娱乐娱乐吧,说说这种挺无聊的问题???。

二:使用 foreach 遍历

为了方便演示,先上一段测试代码:


            var dict = new Dictionary<int, string>()
            {
                [10] = "A10",
                [20] = "A20",
                [30] = "A30",
                [40] = "A40",
                [50] = "A50"
            };

1. 直接 foreach dict

如果要拿百分比说话,估计有 50%+ 的小伙伴用这种方式,为啥,简单粗暴呗,其他没什么好说的,直接上代码:


            foreach (var item in dict)
            {
                Console.WriteLine($"key={item.Key},value={item.Value}");
            }

b2d3ae89cd9da9c9d77153ba71a0a277.png

这里的 item 是底层在 MoveNext 的过程中用 KeyValuePair 包装出来的,如果你不信的话,看下源码呗:


 public bool MoveNext()
 {
  while ((uint)_index uint)_dictionary._count)
  {
   ref Entry reference = ref _dictionary._entries[_index++];
   if (reference.next >= -1)
   {
    _current = new KeyValuePair(reference.key, reference.value);return true;
   }
  }
 }

2. foreach 中 使用 KeyPairValue 解构

刚才你也看到了 item 是 KeyValuePair 类型,不过??的是 netcore 对 KeyValuePair 进行了增强,增加了 Deconstruct 函数用来解构 KeyValuePair,代码如下:


    public readonly struct KeyValuePair
    {private readonly TKey key;private readonly TValue value;public TKey Key => key;public TValue Value => value;public KeyValuePair(TKey key, TValue value)
        {this.key = key;this.value = value;
        }public void Deconstruct(out TKey key, out TValue value)
        {
            key = Key;value = Value;
        }
    }

有了这个解构函数,你就可以在遍历的过程中直接拿到 key,value,而不是包装的 KeyValuePair,这在 netframework 中可是不行的哈,实现代码如下:


            foreach ((int key, string value) in dict)
            {
                Console.WriteLine($"key={key},value={value}");
            }

a36cf45863a0c8fc6a87cee0373c390e.png

3. foreach keys

前面的例子都是直接对 dict 进行 foreach,其实你还可以对 dict.keys 进行 foreach 遍历,然后通过遍历出的 key 对 dict 进行类索引器读取,代码如下:


            foreach (var key in dict.Keys)
            {
                Console.WriteLine($"key={key},value={dict[key]}");
            }

519bcd9d4779da7e34965d7445a6b452.png

说到这里,不知道你是否有一个潜意识,那就是 dict 只能通过 foreach 进行遍历,真相是不是这样的呢?要寻找答案,还是回头看一下 foreach 是如何进行遍历的。


public struct Enumerator : IEnumerator>, IDisposable, IEnumerator, IDictionaryEnumerator
{public bool MoveNext()
 {while ((uint)_index uint)_dictionary._count)
  {ref Entry reference = ref _dictionary._entries[_index++];if (reference.next >= -1)
   {
    _current = new KeyValuePair(reference.key, reference.value);return true;
   }
  }
  _index = _dictionary._count + 1;
  _current = default(KeyValuePair);return false;
 }
}

仔细看这个 while 循环,你就应该明白,本质上它也是对 entries 数组进行遍历,那底层都用了 while,我是不是可以用 for 来替换然后循环 dict 呢?哈哈,反正就是模仿呗。

三:使用 for 遍历

为了把 MoveNext 中的代码模拟出来,重点在于这条语句:ref Entry reference = ref _dictionary._entries[_index++];, 其实很简单,_entries 数组内容的提取可以用 Linq 的 ElementAt 方法,是不是~~~ ,改造后的代码如下:


            for (int i = 0; i             {
                (int key, string value) = dict.ElementAt(i);

                Console.WriteLine($"key={key},value={dict[key]}");
            }

a36cf45863a0c8fc6a87cee0373c390e.png

接下来是不是很好奇这个 ElementAt 扩展方法是如何实现的,一起看看源码吧。


    public static TSource ElementAt(this IEnumerable source, int index)
    {
        IList list = source as IList;if (list != null)
        {return list[index];
        }if (index >= 0)
        {using (IEnumerator enumerator = source.GetEnumerator())
            {while (enumerator.MoveNext())
                {if (index == 0)
                    {return enumerator.Current;
                    }
                    index--;
                }
            }
        }
    }

从上面代码可以看到,如果当前的 source 没有实现 IList 接口的话,那就是一个巨大的坑,每一次执行 ElementAt 方法,最坏时间复杂度都是 O(N),就拿刚才的 for循环来说,它的最坏时间复杂度就是 O(n!) ,是不是比你想象的要恐怖的多,教训就是多实践,多看看源码~

四:总结

这篇列举了 4 种遍历 dict 的方式,不知你会用到哪几种?要注意的是最后 ElementAt 对 Source 判别上的大坑一定要明白,不要想当然的以为就是 O(N) ,好了,更多的 遍历方式 欢迎补充!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/350102.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[HDU 4666]Hyperspace[最远曼哈顿距离][STL]

题意: 许多 k 维点, 求这些点之间的最远曼哈顿距离. 并且有 q 次操作, 插入一个点或者删除一个点. 每次操作之后均输出结果. 思路: 用"疑似绝对值"的思想, 维护每种状态下各点的计算值, 插入或删除一个点就更新一次每种状态(用 multiset 或 map 或 priority_queue 实…

过滤器匹配符包含单词_Hamcrest包含匹配器

过滤器匹配符包含单词与Hamcrest 1.2相比 &#xff0c;针对Matchers类的Hamcrest 1.3 Javadoc文档为该类的几种方法添加了更多文档。 例如&#xff0c;四个重载的contains方法具有更具描述性的Javadoc文档&#xff0c;如下面所示的两个比较屏幕快照所示。 尽管仅通过尝试就可以…

linux配置4g网络命令_树莓派移动网络连接(配置4G网卡)

1、识别上网卡使用命令lsusb&#xff0c;如果能够识别则可以继续往下。2、安装网卡驱动程序上网卡一般都会带有2个功能&#xff0c;一个是虚拟光驱&#xff0c;用来安装驱动程序&#xff1b;另一个是进行网络连接的modem。在Linux下&#xff0c;需要安装usb-modeswitch驱动程序…

Hibernate 配置详解(5)

9) hibernate.batch_fetch_style: 该配置是hibernate4.2.0新添加的&#xff0c;使用这个设置可以配置hibernate在做batch-fetch的时候&#xff0c;生成SQL的策略。该配置项的可选值为org.hibernate.loader.BatchFetchStyle这个枚举类型中的可选值。所以&#xff0c;目前有三个选…

使用HazelCast进行休眠缓存:JPA缓存基础知识

HazelCast的最大功能之一就是对hibernate二级缓存的支持 。 JPA具有两个级别的缓存。 一级缓存在事务期间缓存对象的状态。 通过查询相同的对象两次&#xff0c;您必须获得第一次获取的对象。 但是&#xff0c;在包含您检索到的对象并访问数据库的复杂查询的情况下&#xff…

mvcc原理_Mysql MVCC实现原理

本文中用到的概念解释数据读取特性不可重复读指一个事务范围内两个相同的查询却返回了不同数据这是由于查询时系统中其他事务修改的提交而引起的幻读在两个连续的查找之间一个并发的修改事务修改了查询的数据集&#xff0c;导致这两个查询返回了不同的结果这是由于查询时系统中…

java数组复制的方式和效率比较

java中&#xff0c;数组的复制有以下三种方式&#xff1a; 1. 调用System.arraycopy&#xff08;Arrays.copyOfRange可以当作第四种&#xff0c;但是底层调用的是System.arraycopy&#xff0c;所以&#xff0c;认为是同一种&#xff0c;下面是Arrays.copyOfRange的方法实现&…

Java命令行界面(第18部分):JCLAP

Giles Winstanley的JCLAP &#xff08; Java命令行参数解析器 &#xff09;是基于Java的命令行处理库的系列文章中介绍的第18个库。 这篇文章的示例基于需要Java 8的 JCLAP 1.4 。 JCLAP主页上指出&#xff1a;“ JCLAP帮助Java开发人员为其应用程序创建易于使用的命令行界面。…

数据拆分_数据拆分,偏方请拿好

小伙伴们好啊&#xff0c;今天老祝和大家分享一个比较特殊的数据拆分实例。先来看一组数据&#xff1a;这是一些从系统中导出的数据&#xff0c;一个序号后面连接一个姓名&#xff0c;但是现在都挤在了一个单元格里。咱们要把这些数据变成下面的效果&#xff1a;接下来&#xf…

sql文字转换全拼_取汉字全拼的SQL函数

/*根据汉字获取全拼1.生成所有读音临时表2.根据Chinese_PRC_CS_AS_KS_WS 排序获取读音*/CREATE function f_GetPinYin(str varchar(100))returns varchar(8000)asbegindeclare re varchar(8000)--生成临时表declare t table(chr nchar(1) collate Chinese_PRC_CS_AS_KS_WS,py n…

jaxb入门_JAXB教程–入门

jaxb入门注意&#xff1a;请查看我们的Java XML绑定JAXB教程– ULTIMATE指南 什么是JAXB&#xff1f; JAXB代表用于XML绑定的Java体系结构。它用于将XML转换为java对象&#xff0c;并将java对象转换为XML。JAXB定义了一个用于在XML文档中读写Java对象的API。与SAX和DOM不同&am…

P2863 [USACO06JAN]牛的舞会The Cow Prom

题目描述 The N (2 < N < 10,000) cows are so excited: its prom night! They are dressed in their finest gowns, complete with corsages and new shoes. They know that tonight they will each try to perform the Round Dance. Only cows can perform the Round D…

call需要多大带宽 video_LTE杂谈之IMS voice 和video call流程

pan >SIP Message Logged Bytes 1951Message ID IMS_SIP_INVITEResponse Code INFORMAL_RESPONSE (0)CM Call ID 2SIP Call ID 842064754_23544448882409:8804:8000:186e:9fb:f711:a6d6:ead会话标识&#xff0c;整个流程不变Sip Message INVITEtel:10086;phone-context…

取消堆集以提高延迟并减少AWS账单

大多数性能问题可以通过几种不同的方式解决。 多数人都容易理解和应用许多适用的解决方案。 一些解决方案&#xff0c;例如从JVM管理的堆中删除某些数据结构&#xff0c;则更为复杂。 因此&#xff0c;如果您不熟悉此概念&#xff0c;我建议您继续学习我们最近如何减少应用程序…

python 环境常用指令(updating...)

# 配置pip 源 mkdir -p ~/.pip && cat >> pip.conf <<EOF [global] timeout 60 index-url https://pypi.doubanio.com/simple EOF # pyenv 安装 所需依赖&#xff1a; yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel…

shell 删除了hdfs 文件,在HDFS上删除超过10天的文件

Is there a way to delete files older than 10 days on HDFS?In Linux I would use:find /path/to/directory/ -type f -mtime 10 -name *.txt -execdir rm -- {} \;Is there a way to do this on HDFS? (Deletion to be done based on file creation date)解决方案Solution…

mysql使用方法_Mysql的常用用法

一、mysql中limit的用法详解[数据分页常用]在我们使用查询语句的时候&#xff0c;经常要返回前几条或者中间某几行数据&#xff0c;这个时候怎么办呢&#xff1f;不用担心&#xff0c;mysql已经为我们提供了这样一个功能。SELECT * FROM table LIMIT [offset,] rows | rows OF…

MTK 移植泰文输入法

1.移植zi输入法 1.1 在文件..\make\XXX_GPRS.mak中 讲输入方式改为MMI_ZI XXX_LANGUAGE EN_SM_THAI INPUT_METHOD MMI_XI 1.2在MMI_feature.h 打开相应的ZI语言输入法的宏开关&#xff0c; #if defined(CFG_MMI_LANG_THAI) && ((CFG_MMI_LANG_THAI __ON__)||(CFG_MM…

java中无法推断类型参数_Java中的推断异常

java中无法推断类型参数借用和窃取其他语言的概念和想法总是很高兴的。 Scala的Option是我真正喜欢的一个主意&#xff0c;因此我用Java编写了一个实现。 它包装了一个可能为null或不为null的对象&#xff0c;并提供了一些可用于某种分类功能的方法。 例如&#xff0c;isDefine…

H3C 三种生成树协议特性的比较

转载于:https://www.cnblogs.com/fanweisheng/p/11153361.html