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}"); }
这里的 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}"); }
3. foreach keys
前面的例子都是直接对 dict 进行 foreach,其实你还可以对 dict.keys 进行 foreach 遍历,然后通过遍历出的 key 对 dict 进行类索引器读取,代码如下:
foreach (var key in dict.Keys) { Console.WriteLine($"key={key},value={dict[key]}"); }
说到这里,不知道你是否有一个潜意识,那就是 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]}"); }
接下来是不是很好奇这个 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) ,好了,更多的 遍历方式 欢迎补充!
c标签foreach遍历list_遍历 Dictionary,你会几种方式?相关推荐
- jstl标签forEach的用法--遍历java的集合
再讲<c:forEach>之前,现讲一下让EL表达式生效的语句 <% @ page isELIgnored="false"%>这句语句在你想让EL表达式生效 ...
- Java中遍历Map集合的5种方式总结
这篇文章主要给大家介绍了关于Java中遍历Map集合的5种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值. 方式一 通过Map.keySet使用iterator遍历 ...
- 【C语言】二维数组遍历的3种方式
#include <math.h> #include <stdio.h> #include <stdlib.h>#define ROW 2 #define COL ...
- foreach 实现 MyBatis 遍历集合与批量操作数据
一.写在前面 MyBatis 动态 SQL 的一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候.foreach允许你指定一个集合,声明可以在元素体内使用的集合项(item)和 ...
- java for数组遍历数组_Java foreach操作(遍历)数组
语法: 我们分别使用 for 和 foreach 语句来遍历数组 运行结果: 练习: import java.util.Arrays; public class HelloWorld { public ...
- 原生JS forEach()和map()遍历的区别以及兼容写法
一.原生JS forEach()和map()遍历 共同点: 1.都是循环遍历数组中的每一项. 2.forEach() 和 map() 里面每一次执行匿名函数都支持3个参数:数组中的当前项item,当前 ...
- Java中forEach, 用来遍历数组
这里的for是Java中forEach, 用来遍历数组的.for(int i : d) 就是遍历int型数组d的 每一次访问数组d的时候读取的数据放入int型的i中.和for(int i=0;i< ...
- foreach lambda写法_Java8新特性之forEach+Lambda 表达式遍历Map和List
这是Java8系列的第二篇,今天来说一下Java8中forEach的简单使用.我们使用对比的方式来看应该会看得更加清楚,更能理解: 一.遍历Map ============Java8之前的方式==== ...
- JavaScript中遍历数组的for for-in和forEach三种方式
JavaScript中遍历数组的for for-in和forEach三种方式 for循环 let arr = [1,2,3,4,5,6];for(let i = 0; i < arr.lengt ...
最新文章
- DNC-cs6200 ospfv3
- 终端文件夹跳转工具autojump
- grabcut.cpp:380: error: (-215) !bgdSamples.empty() !fgdSamples.empty() in function initGMMs
- 科大讯飞语音引擎_科大讯飞的1024:语音技术进一步突破,发布专用芯片
- php excel 导入 显示,php Excel 导入
- XML 命名空间以及它们如何影响 XPath 和 XSLT (Extreme XML)
- node-mysql_Nodejs与MySQL交互(felixge/node-mysql)
- RegisterWaitForSingleObject的使用
- 95社区(对接第三方社区)
- 苹果如何将图片转换为文字手机
- java五子棋技术路线,一位老码农的编程简史
- 电脑文件管理——XYplorer
- PV,V,UV的概念,采集数据
- 众里寻他千百度,不如用它来搜库!
- java postgresql date_javapostgresql时区总结
- 机器学习算法工程师到底应该学哪个编程语言?
- 浙江大学计财处预约报销流程
- Alex Woodie:2019大数据预测
- 最近最开心的一件事情
- onegreen的绿软word2003绿色版删除不掉的解决方案
热门文章
- 注入器 过检测_连云港管道检测服务
- 计算机应用基础人才培养方案,1. 培养方案(计算机应用基础课程).doc
- 转译和编译_10个有趣又能编译为JavaScript的语言,你用过哪些?
- 光纤收发器长距离的传输过程出现死机的解决方案
- 【渝粤题库】陕西师范大学200681C语言程序设计 作业(高起专、高起本)
- 【渝粤题库】广东开放大学 会展概论 形成性考核
- sougou ubuntu 优麒麟_搜狗输入法 Linux – V2.3 版发布,完美适配优麒麟 19.10
- 基于java家教管理系统_基于jsp的家教信息管理-JavaEE实现家教信息管理 - java项目源码...
- C++判断是否为素数、求一个数的因数、质因数分解
- 图神经网络PGL助力国民级音乐App,创新迭代千亿级推荐系统(人工智能应用案例)