Unity 实现一个内存紧凑,高效,兼容度高,支持序列化的Map
前言
从Es5 js源码里搬过来的,起初没想到这么好用,直到用Unity内的Dictionary<K,V> 序列化的时候频频报错,iOS上也总有些乱七八糟的问题,在多人帧同步的项目中,由于桶结构的无序处理 ( Unity内部的字典是桶结构实现的) 所以禁止使用
随后我又尝试将STL里的红黑树搬过来用,结果性能还不如双列表。。。。, 果真是大道至简,越简单的反倒约好用
源码
支持,增删改查,适配所有序列化,Json, Protobuf,在帧同步项目中也可以安心使用,因为它是数组实现的,你可以通过内置的Foreach去遍历它,他是有序遍历的
public class Es5Map<K, V> where K : IEquatable<K>
{
private List<K> keys = new List<K>();
private List<V> values = new List<V>();
public void Set( K key, V value )
{
keys.Add( key );
values.Add( value );
}
public V Get( K key )
{
int index = keys.IndexOf( key );
if ( index < 0 ) return default( V );
return values[ index ];
}
public bool Has( K key ) => keys.Contains( key );
public void Del( K key )
{
int index = keys.IndexOf( key );
if ( index < 0 ) return;
values.RemoveAt( index );
keys.RemoveAt( index );
}
public int Count => keys.Count;
public List<K> Keys => keys;
public List<V> Values => values;
public void Foreach( Action<K, V> action )
{
for ( int i = 0; i < keys.Count; i++ )
{
action( keys[ i ], values[ i ] );
}
}
}
先说说它的优点哈
-
空间效率:双列表结构通过将键和值分开存储,可以减少空间占用,尤其是当字典的键和值比较简单时。如果每个键值对都存储在一个元组或其他结构中,这可能会增加内存开销。
-
简单性:双列表的实现比较简单,通常只需要两个列表,分别存储键和值。这种结构不依赖复杂的数据结构,便于理解和实现。
-
快速查找:如果使用一个列表存储键,而另一个列表存储对应的值,可以通过索引直接访问值,查询操作的时间复杂度通常为O(n),与哈希表相比稍微慢一些,但对小规模数据集或特定场景可能足够高效。
-
顺序访问:双列表可以保持插入的顺序,对于某些应用场景,按插入顺序访问键值对是有用的,而哈希表通常无法保证顺序(除非是有序哈希表)。
-
避免哈希冲突:哈希表实现字典时,哈希冲突是一个需要处理的问题,而双列表没有哈希函数的概念,因此没有哈希冲突问题。
再谈谈的缺点
查找效率和扩展性方面,相对于哈希表,性能会有所下降。
最后是我给的几点建议哈
- 如果是多人同步的项目,要求不能使用字典,那么我推荐使用这个方案
- 如果你的项目中存储的数据中需要用到字典结构,我推荐你使用这个方案,传统的字典会有各种序列化的问题
- 如果你的项目只是一个本地的,且比较轻量,本地存储又用不到任何字典相关的数据,那推荐你使用传统字典,它查询的方式Hash更有效率