zoukankan      html  css  js  c++  java
  • 自己动手,实现一种类似List<T>的数据结构(二)

    前言:

    首先,小匹夫要祝各位看官圣诞快乐,新年愉快~。上一篇文章《自己动手,实现一种类似List<T>的数据结构(一)》 介绍了一下不依靠List<T>实现的各种接口,仿造一个轻量级数据结构的过程。可能有的看官会有一些疑问,例如一些功能可以通过Linq提供的拓展来实现呀。此言不虚但也不全对,为了我们在工作中能方便的操作集合而提供的这些拓展方法(包括我们自己也可以构建的拓展方法),例如 Where,Any,Max,All...balalbala等等这些方法都是针对IEnumerable的对象进行扩展的,也就是说需要实现 IEnumerable接口。但是前面已经说了,小匹夫的用意是不实现各种List<T>继承的接口。另外小匹夫的初衷是仿造和拓展 List<T>,将工作中需要使用到的各种功能集成到一个类中,所以有些现成的拓展方法不需要,有一些没有的方法小匹夫也会自己实现一下(当然不是通过给现成的类添加拓展方法这种方式)。当然这篇文章介绍的东西还不成熟,需要慢慢完善,小匹夫也是把这个当做一个学习和实践的机会。好啦,解释完毕,那就介绍下今天的内容吧:

    1. 实现的方法的名称和说明列
    2. 增加了3个委托来抽象3种情况。
    3. Map:通过委托把EggArray<T>中的每个值映射到一个新的EggArray<T>中
    4. Difference:返回的值来自EggArray<T>中,但同时不是传入的Other里面的值
    5. Invoke:在EggArray<T>的每个元素上执行methodName方法。
    6. Pluck:萃取EggArray<T>中某字段值,返回一个数组,由于字段类型不确定,所以需要装箱。
    7. 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 initialization
        void 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

    装模作样的声明一下:本博文章若非特殊注明皆为原创,若需转载请保留原文链接及作者信息慕容小匹夫

  • 相关阅读:
    存储过程中执行动态Sql语句
    模拟alert和confirm
    SignalR
    Html5实践之EventSource
    Java路径操作具体解释
    HDU 1330 Nearest Common Ancestors(求两个点的近期公共祖先)
    Graph(2014辽宁ACM省赛)
    基于注解的Spring MVC整合Hibernate(所需jar包,spring和Hibernate整合配置,springMVC配置,重定向,批量删除)
    W5500问题集锦(二)
    Android Fragment 简单实例
  • 原文地址:https://www.cnblogs.com/murongxiaopifu/p/4176620.html
Copyright © 2011-2022 走看看