【Unity3D数据集合】(三)字典Dictionary和哈希表Hashtable学习

146 阅读8分钟

这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

推荐阅读

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

一、前言

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

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

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

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

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

二、字典和哈希表集合介绍

1、字典Dictionary

字典是一种典型的键值对类型的数据结构,每一个元素都是由一个键值对(键key和值value)组成。

这种数据结构可以通过某个键来访问元素,所以字典也被称为映射或散列表。

字典的主要特性是根据键快速查找值,也可以自由添加和删除元素,这有点像List,但跟List不同的是,List是连续存储,直接定址的。 字典像链表,非连续存储,所以删除元素不需要移动后续元素,就没有在内存中移动后续元素的性能开销。

通过键来检索值的速度是非常快的,接近于 O(1),这是因为 Dictionary 类是作为一个哈希表来实现的,Dictionary 没有顺序之分,这一点不同于list列表,有顺序之分。

键必须是唯一的,而值不需要唯一。

字典中的键和值都是object类型,所以可以是任何类型(比如:string、int、自定义类型等等)

2、哈希表Hashtable

哈希表Hashtable类实现了IDictionary接口,集合中的值也是以键值对(key/value)的形式存取的。

哈希表,也称为散列表,在该集合中每一个元素都是由键值对(key/value)的形式存放值。

需要注意的是,key是区分大小写的。

哈希表Hashtable中的键和值为object类型,所以哈希表Hashtable支持任何类型的键值对。

三、字典和哈希表的区别

说了这么多字典和哈希表,可以看出来两者非常的相似,这两个都是键值对的表现形式,那什么时候用字典什么时候用哈希表呢,下面就来看一下两者的区别:

1、多线程区别

单线程用字典,有泛型优势,读取速度快,容量利用更充分; 哈希表单线程写入,多线程读取

2、线程安全

字典非线程安全,必须人为的增加lock语句进行保护,影响效率。 哈希表可以调用Synchronized()方法可以获得完全线程安全的类型。

3、数据插入顺序

字典的排序就是按照插入的排序(注:删除节点后顺序就被打乱了),因此在需要体现顺序的情况下,字典更有效。 哈希表不是按照顺序插入数据的。

4、索引效率

字典在单线程索引数据的时候效率比较高,读取速度快,但是数据量大的时候效率会下降 哈希表的索引方式是经过散列处理的,在数据量大的时候处理效率更高,所以哈希表比较适合运用在做对象缓存,树递归算法的替代等各种需要提升效率的场合。

四、字典初始化

1、字典初始化

泛型集合,主要利用System.Collections.Generic命名空间下的Dictionary<TKey,TValue>创建集合:

Dictionary<TKey,TValue> table = new Dictionary<TKey,TValue>();

这个TKey/TValue,就是要使用的类型,可以是String、Int,比如下面的例子:

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

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

        foreach (KeyValuePair<int, string> item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

2、哈希表初始化

上面的例子已经演示了,如何初始化字典,如何添加数据,下面就看一下哈希表如何初始化:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1,"张三");//添加keyvalue键值对
        table.Add(2,"李四");

        //由于Hashtable每个元素都是一个键/值对,因此元素类型既不是键的类型,也不是值的类型
        //而是DictionaryEntry类型
        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

字典和哈希表使用方法基本一致。

哈希表与字典不同的是,哈希表不需要一开始就定义键值对的类型,甚至可以key的类型不一致,比如:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");//添加keyvalue键值对
        table.Add("王五", "李四");
        table.Add(1.357f, 32);

        //由于Hashtable每个元素都是一个键/值对,因此元素类型既不是键的类型,也不是值的类型
        //而是DictionaryEntry类型
        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

在这里插入图片描述 这样的好处是,不用在一开始就思考key和value的类型,因为哈希表是以散列表形式存放,所以更加灵活。

五、字典和哈希表的增删改查

1、查找数据

字典 通过key键寻找:

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

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

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

通过循环寻找:

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

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

        foreach (KeyValuePair<int, string> item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

哈希表 通过key值寻找:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();
        table.Add(1, "张三");
        table.Add("王五", "李四");
        table.Add(1.357f, 32);

        Debug.Log(table[1.357f]);
    }
}

通过循环寻找:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");//添加keyvalue键值对
        table.Add("王五", "李四");
        table.Add(1.357f, 32);

        //由于Hashtable每个元素都是一个键/值对,因此元素类型既不是键的类型,也不是值的类型
        //而是DictionaryEntry类型
        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

2、修改数据

字典 可以直接通过key进行数据修改:

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

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

        table[1] = "王五";
        Debug.Log(table[1]);
    }
}

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

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

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

        foreach (KeyValuePair<int, string> item in table)
        {
            if (item.Key > 0)
            {
                table[item.Key] = "修改名字";
            }
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

哈希表 通过key改:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");
        table.Add(2, "李四");
        table.Add(3.45, "王五");

        table[3.45] = "赵六";
    }
}

循环改:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");
        table.Add(2, "李四");
        //table.Add(3.45, "王五");

        foreach (DictionaryEntry item in table)
        {
            if ((int)item.Key > 1)
            {
                Debug.Log(item.Key + " " + item.Value);
            }
        }
    }
}

因为哈希表里面的键值都为object类型,所以进行数值计算的时候都要进行装箱拆箱运算。

如果类型不一致,还会导致装箱拆箱错误。

所以,一定要注意数值类型。

3、增加数据

字典 可以通过Add来增加数据:

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

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

        foreach (KeyValuePair<int, string> item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }

        table.Add(3, "王五");

        foreach (KeyValuePair<int, string> item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

哈希表 可以通过Add来增加数据:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");
        table.Add(2, "李四");
        

        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }

        table.Add(3.45, "王五");//增加数据
        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

4、删除数据

字典 使用Remove删除指定key键的键值对数据元素:

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

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

        foreach (KeyValuePair<int, string> item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }

        table.Remove(1);

        foreach (KeyValuePair<int, string> item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

哈希表 使用Remove删除指定key键的键值对数据元素:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");
        table.Add(2, "李四");


        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }

        table.Remove(3.45);//删除数据
        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

六、字典和哈希表的常见函数

1、排序

对哈希表进行排序,先将哈希表转化成ArrayList,然后使用Sort函数进行排序:

using System.Collections;
using System.Collections.Generic;//使用Hashtable时,必须引入这个命名空间
using UnityEngine;

public class Demo5 : MonoBehaviour
{
    Hashtable table;
    void Start()
    {
        table = new Hashtable();//创建一个Hashtable实例
        table.Add(1, "张三");
        table.Add(3, "李四");
        table.Add(2, "王五");


        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }

        ArrayList akeys = new ArrayList(table.Keys);
        akeys.Sort();

        foreach (DictionaryEntry item in table)
        {
            Debug.Log(item.Key + " " + item.Value);
        }
    }
}

2、其他属性和方法

属性或方法作用
Count集合中存放的元素的实际个数
void Add(object key,object value)向集合中添加元素
void Remove(object key)根据指定的 key 值移除对应的集合元素
void Clear()清空集合
ContainsKey (object key)判断集合中是否包含指定 key 值的元素
ContainsValue(object value)判断集合中是否包含指定 value 值的元素