推荐阅读

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

在日常开发中,常常会用到数据集合,那么数据集合是什么呢,数据集合也没有想象中那么复杂。

数据集合就是专门用来存储数据、检索数据,以及对数据一系列操作的类。

这些类有:ArrayList数组、List列表、Queue队列、Dictionary字典、Hashtable哈希表、Stack堆栈。

在开发中,每种数据集合都有优缺点,今天就将这些数据集合进行归纳总结。

一是方便自己捋顺思路,二是可以帮助到对此理解不清晰的开发者。

这是本系列文章的第二篇:

【Unity3D数据集合】(一)数组集合Array学习
【Unity3D数据集合】(二)列表集合List及ListArray学习
【Unity3D数据集合】(三)字典Dictionary和哈希表Hashtable学习
【Unity3D数据集合】(四)堆栈Stack和队列Queue学习
【Unity3D数据集合】(五)链表LinkedList数据集合学习
【Unity3D数据集合】(六)散列集合HashSet和排序集合SortedSet学习
【Unity3D数据集合】(七)排序列表SortedList和排序字典SortedDictionary学习
【Unity3D数据集合】(八)点阵列BitArray学习

二、列表集合介绍

列表List,是一个泛型集合,泛型集合是C#2.0之后的一个重要概念,是该语言很重要的一部分。

那么什么是泛型呢?

泛型是C# 2.0中新增元素,主要用于解决一系列类似的问题,这种机制允许将类名作为参数传递给泛型类型,并生成相应的对象,从而得到一个新的类型定义。

那么泛型有什么好处呢?

在没有泛型之前,如果要实现集合比较常见有两种方式:
1、使用ArrayList,将对象放入ArrayList,但由于集合中的项是Object类型,因此每次使用都需要进行繁琐的类型转换,这其中就会出现多次装箱拆箱,影响效率。
2、使用自定义集合类,从CollectionBase抽象类继承一个自定义类,通过对IList对象进行封装实现强类型集合,这种方式需要在每种集合类型中写一个相对应的自定义类,工作量,效率低。

而泛型集合的出现就较好的解决了上述问题,只需一行代码便能创建指定类型的集合。

泛型的增加,极大的增加了面向对象编程的效率和灵活性,不会强行对值类型进行装箱和拆箱或对引用类型进行向下强制类型转换,所以性能得到提高。

三、列表数据初始化

泛型类初始化

泛型集合,主要利用System.Collections.Generic命名空间下的List泛型创建集合:

List<T> table = new List<T>();

这个T,就是要使用的类型,可以是String、Int,也可以是用户自定义类型,比如下面的例子:

using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<Person> persons = new List<Person>();
    void Start()
    {
        Person p1 = new Person("张三",18);
        Person p2 = new Person("李四", 19);
        persons.Add(p1);
        persons.Add(p2);
        for (int i = 0; i < persons.Count; i++)
        {
            Debug.Log(persons[i].Name);
        }
    }
}
public class Person
{
    private string name;
    private int age;
    public string Name
    {
        get { return name; }
    }
    public int Age
    {
        get { return age; }
    }
    public Person(string Name,int Age)
    {
        this.name = Name;
        this.age = Age;
    }
}

ArrayList初始化

上面的例子已经演示了,如何初始化数组,如何添加数据,下面就看一下ArrayList如何初始化:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    ArrayList table;
    void Start()
    {
        table = new ArrayList();
        table.Add("张三");
        table.Add("李四");

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }
    }
}

ArrayList和List使用方法基本一致。

ArrayList是数组的优化版,去掉了数组不能增加长度的缺点,但是ArrayList将每个数据元素都作为一个object对象,所以在操作ArrayList的时候,总是要进行装箱拆箱,影响效率。

所以,才出现了List,List不会强行对值类型进行装箱和拆箱或对引用类型进行向下强制类型转换,所以性能得到提高。

四、列表数据的增删改查

查找数据

访问数据,可以使用下标进行访问:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<string> table;
    void Start()
    {
        table = new List<string>();
        table.Add("张三");
        table.Add("李四");

        Debug.Log(table[0]);
    }
}

查找数据,就需要在循环中进行查找了,比如找到数组所有大于10的元素:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(12);
        table.Add(24);
        table.Add(31);
        table.Add(35);


        for (int i = 0; i < table.Count; i++)
        {
            if (table[i] > 10)
            {
                Debug.Log(table[i]);
            }
        }
    }
}

修改数据

可以直接通过下标进行数据修改:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(12);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        table[2] = 10;
    }
}

也可以在循环中,找到对应的数据进行修改:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(12);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        table[2] = 10;

        for (int i = 0; i < table.Count; i++)
        {
            if (table[i] > 10)//找到数组中数据大于10的元素
            {
                table[i] += 10;//让数据元素加10
                Debug.Log(table[i]);
            }
        }
    }
}

增加数据

可以通过Add来增加数据:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(12);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }

        //增加元素
        table.Add(50);
        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }
    }
}

也可以使用AddRange,将一个泛型集合的所有元素到指定泛型集合末尾:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    List<int> table2;
    void Start()
    {
        table = new List<int>();
        table.Add(12);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        table2 = new List<int>();
        table2.Add(12);
        table2.Add(24);

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }

        //增加元素
        table.AddRange(table2);
        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }
    }
}

删除数据

使用Remove、RemoveAt、RemoveRange、RemoveAll进行删除数据元素:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(12);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }

        table.Remove(12);//删除一个值
        table.RemoveAt(0);//删除下标为index的元素
        table.RemoveRange(3, 2);//从下标index开始,删除count个元素
        table.RemoveAll(value => value > 10);//删除所有匹配到的项
    }
}

五、列表集合的常见函数

排序

使用Sort函数进行排序:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(55);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }

        table.Sort();

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }
    }
}

插入数据

使用Insert插入数据:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(55);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        table.Insert(2, 88);

        for (int i = 0; i < table.Count; i++)
        {
            Debug.Log(table[i]);
        }
    }
}

返回索引位置

使用IndexOf方法取得一个元素所在列表中的索引位置

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    List<int> table;
    void Start()
    {
        table = new List<int>();
        table.Add(55);
        table.Add(24);
        table.Add(31);
        table.Add(35);

        Debug.Log(table.IndexOf(24));
    }
}

相同作用的还有LastIndexOf这个是从后往前搜索,搜索到满足条件的就停止,上面的两个方法,如果没有找到指定元素就返回-1

六、列表集合的优缺点

优点

内存上都是连续摆放;不定长;泛型,保证类型安全,避免装箱拆箱

缺点

增删慢