如果你有以下需求:
1. 需要对Dictionary进行遍历的同时移除或者添加元素
2. 需要按顺序遍历Dictionary并且保证先入先出
3. 需要即时的获取字典内的元素数量,即时增删
如果你觉得好,请给我的框架点一个免费的star,球球啦
Yueh0607 - AirFramework
动态字典实现
/********************************************************************************************
* Date : 2023.1.30
* Description :
* 可顺序遍历且可以随机移除的队列
*
* 遍历方法例程:
*
_modules.ResetTraversalCount();
int traversalCount = _modules.TraversalCount;
for (int i = 0; i < traversalCount; ++i)
{
if (_modules.TryDequeue(out IModule module, out Type key))
{
module.OnUpdate();
_modules.TryEnqueue(key, module);
}
}
*
*
********************************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
namespace AirFramework
{
public class DynamicDictionary<T, K> : IEnumerable<KeyValuePair<T, K>> where T : notnull
{
//队列顺序
private readonly Queue<T> queue;
//实际存储键值对,即时
private readonly Dictionary<T, K> dictionary;
//临时移除状态
private readonly Dictionary<T, int> state;
/// <summary>
/// 真正剩余元素数量
/// </summary>
public int Count => dictionary.Count;
/// <summary>
/// 遍历出队的次数
/// </summary>
public int TraversalCount { get; private set; } = 0;
/// <summary>
/// 刷新遍历数量,在每次遍历之前都要进行一次刷新以校准遍历数量
/// </summary>
public int ResetTraversalCount() => TraversalCount = queue.Count;
public DynamicDictionary()
{
queue = new Queue<T>();
dictionary = new Dictionary<T, K>();
state = new Dictionary<T, int>();
}
/// <summary>
/// 通过自定义比较器来提高字典比较效率的构造方式
/// </summary>
/// <param name="equalityComparer"></param>
public DynamicDictionary(IEqualityComparer<T> equalityComparer)
{
queue = new Queue<T>();
dictionary = new Dictionary<T, K>(equalityComparer);
state = new Dictionary<T, int>(equalityComparer);
}
/// <summary>
/// 入队
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Enqueue(T key, K value)
{
if (TryEnqueue(key, value)) return;
throw new InvalidOperationException("The operation on an empty container is invalid");
}
/// <summary>
/// 尝试入队
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryEnqueue(T key, K value)
{
if (!dictionary.TryAdd(key, value))
{
return false;
}
queue.Enqueue(key);
return true;
}
/// <summary>
/// 从队中移除
/// </summary>
/// <param name="key"></param>
public void Remove(T key)
{
if (!TryRemove(key))
{
throw new InvalidOperationException("The operation on an empty container is invalid");
}
}
/// <summary>
/// 尝试从队中移除
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool TryRemove(T key)
{
if (dictionary.ContainsKey(key))
{
dictionary.Remove(key);
if (state.ContainsKey(key)) state[key]++;
else state.Add(key, 1);
return true;
}
return false;
}
/// <summary>
/// 尝试获取队首
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public bool TryPeek(out K result)
{
do
{
if (queue.TryPeek(out var key))
{
if (state.TryGetValue(key, out int count))
{
state[key] = --count;
if (TraversalCount > 0) TraversalCount--;
if (count == 0) state.Remove(key);
queue.Dequeue();
}
else return dictionary.TryGetValue(key, out result);
}
else
{
result = default;
return false;
}
}
while (true);
}
/// <summary>
/// 获取队首
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public K Peek()
{
if (TryPeek(out var result)) return result;
throw new InvalidOperationException("The operation on an empty container is invalid");
}
/// <summary>
/// 尝试出队
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public bool TryDequeue(out K result)
{
return TryDequeue(out result, out _);
}
/// <summary>
/// 尝试出队
/// </summary>
/// <param name="result"></param>
/// <param name="k"></param>
/// <returns></returns>
public bool TryDequeue(out K result, out T k)
{
if (queue.TryDequeue(out var key))
{
while (state.TryGetValue(key, out var count))
{
state[key] = --count;
if (TraversalCount > 0) TraversalCount--;
if (count == 0) state.Remove(key);
if (!queue.TryDequeue(out key))
{
result = default;
k = default;
return false;
}
}
if (dictionary.TryGetValue(key, out result))
{
k = key;
dictionary.Remove(key);
return true;
}
}
result = default;
k = default;
return false;
}
/// <summary>
/// 出队
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public K Dequeue()
{
if (TryDequeue(out var result))
{
return result;
}
throw new InvalidOperationException("The operation on an empty container is invalid");
}
/// <summary>
/// 访问以K为键的对象
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public K this[T key]
{
get => dictionary[key];
set => dictionary[key] = value;
}
/// <summary>
/// 是否存在以K为键的对象
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool ContainsKey(T key) => dictionary.ContainsKey(key);
/// <summary>
/// 清空
/// </summary>
public void Clear()
{
dictionary.Clear();
queue.Clear();
state.Clear();
}
/// <summary>
/// 无序遍历 不可动态随机移除 迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<KeyValuePair<T, K>> GetEnumerator()
{
return dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return dictionary.GetEnumerator();
}
}
}
配套拓展方法
using System;
namespace AirFramework
{
public static class DynamicDictionaryExtensions
{
/// <summary>
/// 从动态字典获取一个值,如果值不存在则返回传入的默认值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="dictionary"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static K GetValueOrDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, K value = default)
{
if (dictionary.ContainsKey(key))
{
return dictionary[key];
}
return value;
}
/// <summary>
/// 从动态字典获取一个值,如果不存在则添加指定值后返回该值
/// </summary>
/// <typeparam name="T">键类型</typeparam>
/// <typeparam name="K">值类型</typeparam>
/// <param name="dictionary">动态字典</param>
/// <param name="key">键</param>
/// <param name="value">默认值</param>
/// <returns>值</returns>
public static K GetValueOrAddDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, K value = default)
{
if (dictionary.ContainsKey(key))
{
return dictionary[key];
}
dictionary.Enqueue(key, value);
return dictionary[key];
}
/// <summary>
/// 从动态字典获取一个值,如果不存在则添加指定值后返回该值
/// </summary>
/// <typeparam name="T">键类型</typeparam>
/// <typeparam name="K">值类型</typeparam>
/// <param name="dictionary">动态字典</param>
/// <param name="key">键</param>
/// <param name="value">默认值</param>
/// <returns>值</returns>
public static K GetValueOrAddDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, Func<K> getter = null)
{
if (dictionary.ContainsKey(key))
{
return dictionary[key];
}
dictionary.Enqueue(key, getter == null ? default : getter());
return dictionary[key];
}
/// <summary>
/// 尝试从动态字典获取一个值,如果该值存在则返回true并传出Value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="dictionary"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryGetValue<T, K>(this DynamicDictionary<T, K> dictionary, T key, out K value)
{
if (dictionary.ContainsKey(key))
{
value = dictionary[key];
return true;
}
value = default;
return false;
}
/// <summary>
/// 尝试从动态字典获取一个值,如果该值存在则返回true并传出Value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="dictionary"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool GetValueOrDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, out K value)
{
if (dictionary.ContainsKey(key))
{
value = dictionary[key];
return true;
}
value = default;
return false;
}
/// <summary>
/// 尝试从动态字典移除一个值并调用Dispose,如果该值存在则返回true
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="dictionary"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryRemoveAndDispose<T, K>(this DynamicDictionary<T, K> dictionary, T key) where K : IDisposable
{
if (dictionary.TryGetValue(key, out var value))
{
value.Dispose();
return true;
}
return false;
}
/// <summary>
/// 从动态字典移除一个值并调用其Dispose方法,如果该值不存在将引发异常
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="dictionary"></param>
/// <param name="key"></param>
public static void RemoveAndDispose<T, K>(this DynamicDictionary<T, K> dictionary, T key) where K : IDisposable
{
dictionary.Remove(key);
dictionary[key].Dispose();
}
/// <summary>
/// 清空动态字典并调用所有元素的Dispose方法s
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="dictionary"></param>
public static void ClearAndDispose<T, K>(this DynamicDictionary<T, K> dictionary) where K : IDisposable
{
while (dictionary.Count > 0)
{
dictionary.Dequeue().Dispose();
}
}
}
}
动态HashSet的实现
/********************************************************************************************
* Date : 2023.1.30
* Description :
* 可顺序遍历且可以随机移除的队列
*
* 遍历方法例程:
*
_modules.ResetTraversalCount();
int traversalCount = _modules.TraversalCount;
for (int i = 0; i < traversalCount; ++i)
{
if (_modules.TryDequeue(out IModule module))
{
module.OnUpdate();
_modules.TryEnqueue( module);
}
}
*
*
********************************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
namespace AirFramework
{
public class DynamicHashSet<T> : IEnumerable<T> where T : notnull
{
//队列顺序
private readonly Queue<T> queue;
//实际存储键值对,即时
private readonly HashSet<T> hashSet;
//临时移除状态
private readonly Dictionary<T, int> state;
/// <summary>
/// 真正剩余元素数量
/// </summary>
public int Count => hashSet.Count;
/// <summary>
/// 遍历出队的次数
/// </summary>
public int TraversalCount { get; private set; } = 0;
/// <summary>
/// 刷新遍历数量,在每次遍历之前都要进行一次刷新以校准遍历数量
/// </summary>
public int ResetTraversalCount() => TraversalCount = queue.Count;
public DynamicHashSet()
{
queue = new Queue<T>();
hashSet = new HashSet<T>();
state = new Dictionary<T, int>();
}
/// <summary>
/// 通过自定义比较器来提高比较效率的构造方式
/// </summary>
/// <param name="equalityComparer"></param>
public DynamicHashSet(IEqualityComparer<T> equalityComparer)
{
queue = new Queue<T>();
hashSet = new HashSet<T>(equalityComparer);
state = new Dictionary<T, int>(equalityComparer);
}
/// <summary>
/// 入队
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Enqueue(T key)
{
if (TryEnqueue(key)) return;
throw new ArgumentException("Same key exists");
}
/// <summary>
/// 尝试入队
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryEnqueue(T key)
{
if (!hashSet.TryAdd(key)) return false;
queue.Enqueue(key);
return true;
}
/// <summary>
/// 从队中移除
/// </summary>
/// <param name="key"></param>
public void Remove(T key)
{
if (!TryRemove(key)) throw new ArgumentException("error remove key ");
}
/// <summary>
/// 尝试从队中移除
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool TryRemove(T key)
{
if (hashSet.Contains(key))
{
hashSet.Remove(key);
if (state.ContainsKey(key)) state[key]++;
else state.Add(key, 1);
return true;
}
return false;
}
/// <summary>
/// 尝试获取队首
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public bool TryPeek(out T result)
{
do
{
if (queue.TryPeek(out var key))
{
if (state.TryGetValue(key, out int count))
{
state[key] = --count;
if (TraversalCount > 0) TraversalCount--;
if (count == 0) state.Remove(key);
queue.Dequeue();
}
else return hashSet.TryGetValue(key, out result);
}
else
{
result = default;
return false;
}
}
while (true);
}
/// <summary>
/// 获取队首
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public T Peek()
{
if (TryPeek(out var result)) return result;
throw new InvalidOperationException("The operation on an empty container is invalid");
}
/// <summary>
/// 尝试出队
/// </summary>
/// <param name="result"></param>
/// <param name="result"></param>
/// <returns></returns>
public bool TryDequeue(out T result)
{
if (queue.TryDequeue(out var key))
{
while (state.TryGetValue(key, out var count))
{
state[key] = --count;
if (TraversalCount > 0) TraversalCount--;
if (count == 0) state.Remove(key);
if (!queue.TryDequeue(out key))
{
result = default;
return false;
}
}
if (hashSet.Contains(key))
{
result = key;
hashSet.Remove(key);
return true;
}
}
result = default;
return false;
}
/// <summary>
/// 出队
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public T Dequeue()
{
if (TryDequeue(out var result))
{
return result;
}
throw new InvalidOperationException("The operation on an empty container is invalid");
}
/// <summary>
/// 是否存在Key对象
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool Contains(T key) => hashSet.Contains(key);
/// <summary>
/// 清空
/// </summary>
public void Clear()
{
hashSet.Clear();
queue.Clear();
state.Clear();
}
/// <summary>
/// 无序遍历 不可动态随机移除 迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return hashSet.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return hashSet.GetEnumerator();
}
}
}
配套拓展方法
using System;
namespace AirFramework
{
public static class DynamicHashSetExtensions
{
/// <summary>
/// 尝试从动态HashSet移除一个值并调用Dispose,如果该值存在则返回true
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="hashSet"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryRemoveAndDispose<T>(this DynamicHashSet<T> hashSet, T key) where T : IDisposable
{
if (hashSet.Contains(key))
{
key.Dispose();
return true;
}
return false;
}
/// <summary>
/// 从动态字典移除一个值并调用其Dispose方法,如果该值不存在将引发异常
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="K"></typeparam>
/// <param name="hashSet"></param>
/// <param name="key"></param>
public static void RemoveAndDispose<T, K>(this DynamicHashSet<T> hashSet, T key) where T : IDisposable
{
hashSet.Remove(key);
key.Dispose();
}
/// <summary>
/// 清空动态字典并调用所有元素的Dispose方法s
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashSet"></param>
public static void ClearAndDispose<T>(this DynamicHashSet<T> hashSet) where T : IDisposable
{
while (hashSet.Count > 0)
{
hashSet.Dequeue().Dispose();
}
}
}
}