自己动手,实现一种类似ListT的数据结构(二)
前言:
首先,小匹夫要祝各位看官圣诞快乐,新年愉快~。上一篇文章《自己动手,实现一种类似List<T>的数据结构(一)》 介绍了一下不依靠List<T>实现的各种接口,仿造一个轻量级数据结构的过程。可能有的看官会有一些疑问,例如一些功能可以通过Linq提供的拓展来实现呀。此言不虚但也不全对,为了我们在工作中能方便的操作集合而提供的这些拓展方法(包括我们自己也可以构建的拓展方法),例如 Where,Any,Max,All...balalbala等等这些方法都是针对IEnumerable的对象进行扩展的,也就是说需要实现 IEnumerable接口。但是前面已经说了,小匹夫的用意是不实现各种List<T>继承的接口。另外小匹夫的初衷是仿造和拓展 List<T>,将工作中需要使用到的各种功能集成到一个类中,所以有些现成的拓展方法不需要,有一些没有的方法小匹夫也会自己实现一下(当然不是通过给现成的类添加拓展方法这种方式)。当然这篇文章介绍的东西还不成熟,需要慢慢完善,小匹夫也是把这个当做一个学习和实践的机会。好啦,解释完毕,那就介绍下今天的内容吧:
- 实现的方法的名称和说明列表
- 增加了3个委托来抽象3种情况。
- Map:通过委托把EggArray<T>中的每个值映射到一个新的EggArray<T>中。
- Difference:返回的值来自EggArray<T>中,但同时不是传入的Other里面的值
- Invoke:在EggArray<T>的每个元素上执行methodName方法。
- Pluck:萃取EggArray<T>中某字段值,返回一个数组,由于字段类型不确定,所以需要装箱。
- Shuffle:返回一个随机乱序的T[]副本。
那么下面我们就书接上文,继续我们仿照和拓展List<T>的步伐。
Underscore.js的前缘
咦,这不是一篇关于Csharp的文章吗?怎么把JS给干出来?哈哈,当然技术上并没有什么必然的关系,只不过是小匹夫之前使用过cocos2d这套游戏引擎开发过游戏,有一段时间也很痴迷于cocos2d-js这种使用JS就能开发原生游戏的能力。所以也接触了一些js库,对Underscore.js更是情有独钟。所以一提到要模仿List<T>这种内部其实是Array的数据结构,一个灵感就是为何不尝试实现一些Underscore.js数组部分的若干功能呢?所以下表EggArray<T>的新增方法中有部分借鉴于Underscore.js。
新增方法表
新增方法 | 说明 |
First | 返回EggArray<T> 的第一个元素。传递 n参数将返回数组中从第一个元素开始的n个元素 |
Last | 返回EggArray<T> 的最后一个元素。传递 n参数将返回数组中从最后一个元素开始的n个元素 |
Slice | 切割 |
Get | 预留 |
Set | 预留 |
AddFirst | 将对象添加到 EggArray<T> 的起始处。 |
RemoveLast | 从 EggArray<T> 中移除特定对象的最后一个匹配项。 |
ContainsStrict | 确定某元素是否在 EggArray<T> 中。(严格判断是否是同一个对象) |
IndexOfStrict | 搜索指定的对象,并返回整个 EggArray<T> 中第一个匹配项的从零开始的索引。(同上) |
TryGet | 获取指定类型对象 |
LastIndexOf | 搜索指定的对象,并返回整个 EggArray<T> 中第一个匹配项的从结尾开始的索引。 |
Map | 通过委托把EggArray<T>中的每个值映射到一个新的EggArray<T>中 |
Filter | 遍历EggArray<T>中的每个值,返回包含所有通过predicate真值检测的元素值。 |
Without | 返回一个删除所有values值后的 EggArray<T>副本。 |
Find | 在EggArray<T>中逐项查找,返回第一个通过predicate迭代函数真值检测的元素值 |
Every | 如果EggArray<T>中的所有元素都通过predicate的真值检测就返回true。 |
Some | 如果EggArray<T>中有任何一个元素通过 predicate 的真值检测就返回true。 |
Partition | 拆分一个EggArray<T>为两个数组: 第一个数组其元素都满足predicate迭代函数, 而第二个的所有元素均不能满足predicate迭代函数 |
Difference | 返回的值来自EggArray<T>中,但同时不是传入的Other里面的值 |
Uniq | 返回 EggArray<T>去重后的副本 |
Invoke | 在EggArray<T>的每个元素上执行methodName方法。 |
Pluck | 萃取EggArray<T>中元素某属性值,返回一个数组。 |
Shuffle | 返回一个随机乱序的T[]副本 |
Sample | 从 EggArray<T>中产生一个随机样本。传递一个数字表示从EggArray<T>中返回n个随机元素。否则将返回一个单一的随机项。 |
各位看官可以看到,增加了许多挺有趣的功能。为了能将表中的功能名字变成真正的功能,我们还需要对上一篇文章中的变量&属性部分做一些增改,如下我们增加了3个委托来抽象3种情况。
//定义三个委托来处理具体逻辑 public delegate void IterationHandler(T item); public delegate bool IterationBoolHandler(T item); public delegate T IterationVauleHandler(T item);
同时为了能测试我们的功能,我们还要定义一个用来被当做元素测试的类。
//被测试类 public class TargetClass {public int id;public string name;public TargetClass(int id){this.id = id;this.name = "NO. " + id;}public void Hi(){Debug.Log ("say hi");} }
同时还要有一个测试的环境,因为小匹夫是用mac做unity3d的开发,所以就直接使用unity3d的环境了。
/// <summary> /// Egg array test.Based on Unity3D,各个元素的id为0-9 /// </summary> using UnityEngine; using System.Collections; using EggToolkit; public class EggArrayTest : MonoBehaviour {EggArray<TargetClass> testArray = new EggArray<TargetClass>();// Use this for initializationvoid Start () {for(int i = 0; i < 10; i++){TargetClass test = new TargetClass(i);testArray.Add(test);} // Test_Difference(); // Test_Invoke(); // Test_Pluck(); // Test_Shuffle(); // Test_Map(); }void Update () {} }
下面就让小匹夫带领大家分析几个具体的函数,并进行下测试吧。
Map:
使用了IterationVauleHandler这个委托,即需要返回一个T类型的值。
//通过委托把EggArray<T>中的每个值映射到一个新的EggArray<T>中 public EggArray<T> Map(EggArray<T>.IterationVauleHandler handler) {EggArray<T> targetArray = new EggArray<T>(this.capacity);for(int i = 0; i < this.count; i++){T t = handler(this.items[i]);targetArray.Add(t);}return targetArray; }
在EggArrayTest中实现Test_Map这个方法:
void Test_Map() {EggArray<TargetClass> newArray = testArray.Map(delegate(TargetClass item) {TargetClass newItem = new TargetClass(1);newItem.id = item.id * 10;return newItem;});newArray.Foreach(delegate(TargetClass item) {Debug.Log (item.id);}); } //原元素的id为0-9,输出为0,10,20...90
Difference:
调用了Filter方法,其中Filter方法的参数是一个IterationBoolHandler委托,即一个返回bool值的委托。具体可以看Filter的实现。
/// <summary> /// Difference the specified others. ///输出不包含others中元素的EggArray<T> /// </summary> /// <param name="others">Others.</param> public EggArray<T> Difference(EggArray<T> others) {EggArray<T> targetArray = new EggArray<T>();targetArray = this.Filter(delegate(T item) {bool b = !others.Contains(item);return b;});return targetArray; }
在EggArrayTest中实现Test_Difference这个方法:
//作为参数传入的EggArray<T>由testArray的第5,第9这2个元素组成 void Test_Difference() {EggArray<TargetClass> differentArray = new EggArray<TargetClass>();differentArray.Add(testArray.Get(5));differentArray.Add(testArray.Get(9));testArray.Difference(differentArray).Foreach(delegate(TargetClass item) {Debug.Log(item.name);}); } //输出缺少no. 5,no. 9这两个name
Invoke:
在EggArray<T>的每个元素上执行methodName方法。
/// <summary> /// Invoke the specified methodName. /// 每个元素上执行methodName方法,若方法不存在则抛出exception /// </summary> /// <param name="methodName">Method name.</param> public void Invoke(string methodName) {Type t = typeof(T);var method = t.GetMethod(methodName);if(method == null)throw new Exception("没有找到指定的方法哦~,可能不叫" + methodName);for(int i = 0; i < this.count; i++){method.Invoke(this.items[i], null);} }
在EggArrayTest中实现Test_Invoke这个方法:
//调用TargetClass的HI()方法 void Test_Invoke() {testArray.Invoke("Hi"); }//输出:say hi
Pluck:
萃取EggArray<T>中某字段值,返回一个数组,由于字段类型不确定,所以需要装箱。当传入的名称无法查找到该字段时,抛出exception。
/// <summary> /// Pluck the specified fieldName. /// 萃取某字段值,返回一个数组 /// 由于字段类型不确定,所以需要装箱 /// </summary> /// <param name="fieldName">Field name.</param> public object[] Pluck(string fieldName) {Type t = typeof(T);object[] targetArray = new object[this.count];var field = t.GetField(fieldName);if(field == null)throw new Exception("没有找到指定的field哦~,可能不叫" + fieldName);for(int i = 0; i < this.count; i++){object value = field.GetValue(this.items[i]);targetArray[i] = value;}return targetArray; }
在EggArrayTest中实现Test_Pluck这个方法:
//获取各个元素 字段id的值 void Test_Pluck() {object[] testObj = testArray.Pluck("id");string testString = string.Empty;for(int i = 0; i < testObj.Length; i++){testString = testObj[i].ToString();Debug.Log ("field value is " + testString);} }//输出为0-9
Shuffle:
返回一个随机乱序的T[],下面看代码
/// <summary> /// Shuffle this instance. /// 返回一个随机乱序的副本 /// </summary> public T[] Shuffle() {T[] shuffled = new T[this.count];Random random = new Random();for (int index = 0, rand; index < this.count; index++) {rand = random.Next(index);if (rand != index) shuffled[index] = shuffled[rand];shuffled[rand] = this.items[index];}return shuffled; }
在EggArrayTest中实现Test_Shuffle这个方法:
// void Test_Shuffle() {TargetClass[] test = testArray.Shuffle();for(int i = 0; i < test.Length; i++){Debug.Log (test[i].name);} }//默认顺序为NO. 0 ~ NO. 9 //乱序后,见图
好了,这周就到这里~小匹夫最近也在赶项目的途中,所以测试和修改的精力也被消耗了很多。过完元旦之后,再继续~
末了还是要说一声:各位元旦快乐~
完整的代码和测试可以在这里获取:https://github.com/chenjd/Unity3D_EggArray
装模作样的声明一下:本博文章若非特殊注明皆为原创,若需转载请保留原文链接及作者信息慕容小匹夫
转载于:https://www.cnblogs.com/murongxiaopifu/p/4176620.html
自己动手,实现一种类似ListT的数据结构(二)相关推荐
- 交叉熵损失函数的通用性(为什么深度学习DL普遍用它):预测输出与 y 差得越多,L 的值越大,也就是说对当前模型的 “ 惩罚 ” 越大,而且是非线性增大是一种类似指数增长的级别,结论:它对结果有引导性
交叉熵损失函数的通用性(为什么深度学习DL普遍用它):预测输出与 y 差得越多,L 的值越大,也就是说对当前模型的 " 惩罚 " 越大,而且是非线性增大是一种类似指数增长的级别,结 ...
- html服务器框架,一种类似http/html的分布式GUI程序设计框架
笔者构想了一种类似http/html的分布式GUI程序设计框架,适用于WIndows.桌面Linux.Mac OS以及C++,Java,Python等多种支持GUI编程的程序设计系统.但是对于手机小屏 ...
- 【Linux】一种类似迅雷的下载器安装
谷歌chrome浏览器有时会遇到下载链接自动被拦截的问题,在Win系统中可以用"迅雷"来下载某链接,但linux系统中没有迅雷,这里记录一种类似迅雷的下载器--uget和aria2 ...
- 树展示 移动端_一种手机端树形数据结构的展现方法与流程
本发明涉及数据结构的展现领域,尤其涉及一种手机端树形数据结构的展现方法. 背景技术: 在企业中,组织结构表现为部门.员工.职称等一种群体关系图,它形象的反映了企业内部各部门和员工上下左右之间的相互关系 ...
- 仿脉脉PHP源码,php,mysql_如何实现类似脉脉网的二维人际关系,php,mysql,算法,社区,社交 - phpStudy...
如何实现类似脉脉网的二维人际关系 以下是简化的数据和场景 ==========================数据======================== 用户信息: 用户ID[ID] .用户 ...
- 置信区间(Confidence Intervals)是什么?如何计算置信区间?置信区间的两种计算方法是什么?二值样本置信区间如何计算?如何基于bootstrap抽样进行置信区间计算?
置信区间(Confidence Intervals)是什么?如何计算置信区间?置信区间的两种计算方法是什么?二值样本置信区间如何计算?如何基于bootstrap抽样进行置信区间计算? 目录 置信区间( ...
- 一种实现个人微信支付宝二维码收款接口的方法
一种实现个人微信支付宝二维码收款接口的方法 只有企业资质才能申请微信支付宝接口,要想实现自动收款除了想办法搞到企业资质申请官方的微信支付接口外,还可以想办法通过个人收款码来实现. 1.上传个人微信支付 ...
- c#二叉树 取叶子节点个数_两种类似但是原理不同的算法求二叉树的所有叶子节点和...
技术提高是一个循序渐进的过程,所以我讲的leetcode算法题从最简单的level开始写的,然后到中级难度,最后到hard难度全部完. 目前我选择C语言,Python和Java作为实现语言,因为这三种 ...
- 【一种类似labelme自动勾画方式---opencv】
一种自动勾画方式,类似于labelme一样,鼠标点可以自动吸附当前欧式距离最近的边缘点,暂未做做界面,有谁会做界面的欢迎补充. #include<opencv2\opencv.hpp> # ...
最新文章
- boost:进程管理
- Single-Shot Calibration:基于全景基础设施的多相机和多激光雷达之间的外参标定(IROS2021)...
- Windows下使用Dev-C++开发基于pthread.h的多线程程序
- 43、Java动态代理一——动态类Proxy的使用
- ITK:将图像传递给函数
- 查询每个班级排名第三的学生
- 全屏显示的包含webview的页面中弹出的软键盘覆盖输入框的问题
- Firebug Tutorial (Section 3): Script Tab :Javascript Debugging
- 台电u盘量产工具_简单几步,让U盘起死回生
- 操作系统学习总结(超赞!!!)
- 【ios】在真实设备上运行
- assimp android build,使用Android Studio+CMakeLists编译assimp
- 好玩的问答,看看你的年龄阶段哦
- 程序员是如何处理密码的?
- C++ 编译运行报错 error: stray ‘\200’ in program 解决方案
- SilverLight跨域访问及其常用的几种解决方法
- Java语言程序设计课程设计
- 主梁弹性模量计算_轮扣模板计算书(GB51210-2016规范)
- 牛学长iTunes备份密码移除工具
- android 跳转oppo应用中心_Android唤起应用商店并跳转到应用详情页
热门文章
- 【qduoj】C语言课程设计_约瑟夫问题
- 【51Nod - 1279】 扔盘子(思维)(on-p会超时)
- android和ios系统的内存,WP和Saipan系统的流畅程度相当于ios,占用的内存很少,但是为什么要用Android取代它...
- java 学生课程成绩_Java课设--学生成绩管理系统一
- mysql配置日志老化配置_mysql配置-日志大小限制和自动删除
- 服务器虚拟化底层系统安装,Hyper-V是底层的虚拟机程序,位于操作系统和硬件之间,很薄一层...
- Linux简单命令收录(cal,passwd,clear)【下】
- leecode11 盛水最多的容器
- 如何使用redis来实现常见的游戏排行榜
- python sqlserver 数据操作_python对Excel数据进行读写操作