UNIVPLMDataIntegration/Admin.NET/Admin.NET.Core/Utils/Collections/StackExtensions.cs

542 lines
18 KiB
C#
Raw Normal View History

// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 堆栈扩展方法
/// </summary>
public static class StackExtensions
{
/// <summary>
/// 批量入栈
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="items">要入栈的元素集合</param>
/// <exception cref="ArgumentNullException">堆栈或元素集合为空时抛出</exception>
public static void PushRange<T>(this Stack<T> stack, IEnumerable<T> items)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(items);
foreach (var item in items)
{
stack.Push(item);
}
}
/// <summary>
/// 批量入栈(保持集合的原始顺序)
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="items">要入栈的元素集合</param>
/// <exception cref="ArgumentNullException">堆栈或元素集合为空时抛出</exception>
public static void PushRangeReversed<T>(this Stack<T> stack, IEnumerable<T> items)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(items);
// 反转顺序入栈,使得弹出时保持原始顺序
var itemsArray = items.ToArray();
for (var i = itemsArray.Length - 1; i >= 0; i--)
{
stack.Push(itemsArray[i]);
}
}
/// <summary>
/// 批量出栈
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="count">要出栈的元素数量</param>
/// <returns>出栈的元素集合</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
/// <exception cref="ArgumentOutOfRangeException">数量小于0或大于堆栈长度时抛出</exception>
public static IEnumerable<T> PopRange<T>(this Stack<T> stack, int count)
{
ArgumentNullException.ThrowIfNull(stack);
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "数量不能小于0");
}
if (count > stack.Count)
{
throw new ArgumentOutOfRangeException(nameof(count), "数量不能大于堆栈长度");
}
var result = new List<T>(count);
for (var i = 0; i < count; i++)
{
result.Add(stack.Pop());
}
return result;
}
/// <summary>
/// 尝试出栈多个元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="count">要出栈的元素数量</param>
/// <param name="items">出栈的元素集合</param>
/// <returns>是否成功出栈指定数量的元素</returns>
public static bool TryPopRange<T>(this Stack<T> stack, int count, out IEnumerable<T> items)
{
items = [];
if (count < 0 || count > stack.Count)
{
return false;
}
var result = new List<T>(count);
var tempItems = new List<T>();
for (var i = 0; i < count; i++)
{
if (stack.TryPop(out var item))
{
result.Add(item);
tempItems.Add(item);
}
else
{
// 恢复已出栈的元素
for (var j = tempItems.Count - 1; j >= 0; j--)
{
stack.Push(tempItems[j]);
}
return false;
}
}
items = result;
return true;
}
/// <summary>
/// 清空堆栈并返回所有元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <returns>堆栈中的所有元素</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
public static IEnumerable<T> DrainToList<T>(this Stack<T> stack)
{
ArgumentNullException.ThrowIfNull(stack);
var result = new List<T>(stack.Count);
while (stack.Count > 0)
{
result.Add(stack.Pop());
}
return result;
}
/// <summary>
/// 安全地查看堆栈顶部元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="item">堆栈顶部元素</param>
/// <returns>是否成功查看</returns>
public static bool TryPeek<T>(this Stack<T> stack, out T? item)
{
item = default;
if (stack.Count == 0)
{
return false;
}
item = stack.Peek();
return true;
}
/// <summary>
/// 安全地查看多个顶部元素(不出栈)
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="count">要查看的元素数量</param>
/// <returns>顶部指定数量的元素</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
/// <exception cref="ArgumentOutOfRangeException">数量小于0或大于堆栈长度时抛出</exception>
public static IEnumerable<T> PeekRange<T>(this Stack<T> stack, int count)
{
ArgumentNullException.ThrowIfNull(stack);
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "数量不能小于0");
}
if (count > stack.Count)
{
throw new ArgumentOutOfRangeException(nameof(count), "数量不能大于堆栈长度");
}
var items = stack.ToArray();
return items.Take(count);
}
/// <summary>
/// 检查堆栈是否为空
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <returns>堆栈是否为空</returns>
public static bool IsEmpty<T>(this Stack<T> stack)
{
return stack?.Count == 0;
}
/// <summary>
/// 检查堆栈是否不为空
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <returns>堆栈是否不为空</returns>
public static bool IsNotEmpty<T>(this Stack<T> stack)
{
return stack?.Count > 0;
}
/// <summary>
/// 将堆栈转换为数组,保持堆栈顺序
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <returns>包含堆栈所有元素的数组</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
public static T[] ToArrayPreserveOrder<T>(this Stack<T> stack)
{
ArgumentNullException.ThrowIfNull(stack);
return [.. stack];
}
/// <summary>
/// 复制堆栈
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">原堆栈</param>
/// <returns>复制的新堆栈</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
public static Stack<T> Clone<T>(this Stack<T> stack)
{
ArgumentNullException.ThrowIfNull(stack);
// 保持原始堆栈的顺序
var items = stack.ToArray();
return new Stack<T>(items);
}
/// <summary>
/// 查找堆栈中是否包含满足条件的元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="predicate">匹配条件</param>
/// <returns>是否包含满足条件的元素</returns>
/// <exception cref="ArgumentNullException">堆栈或条件为空时抛出</exception>
public static bool Contains<T>(this Stack<T> stack, Func<T, bool> predicate)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(predicate);
return stack.Any(predicate);
}
/// <summary>
/// 统计堆栈中满足条件的元素数量
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="predicate">匹配条件</param>
/// <returns>满足条件的元素数量</returns>
/// <exception cref="ArgumentNullException">堆栈或条件为空时抛出</exception>
public static int Count<T>(this Stack<T> stack, Func<T, bool> predicate)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(predicate);
return stack.Count(predicate);
}
/// <summary>
/// 对堆栈中的每个元素执行指定操作(从顶部到底部)
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="action">要执行的操作</param>
/// <exception cref="ArgumentNullException">堆栈或操作为空时抛出</exception>
public static void ForEach<T>(this Stack<T> stack, Action<T> action)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(action);
foreach (var item in stack)
{
action(item);
}
}
/// <summary>
/// 对堆栈中的每个元素执行指定操作(带索引,从顶部到底部)
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="action">要执行的操作,参数为元素和索引</param>
/// <exception cref="ArgumentNullException">堆栈或操作为空时抛出</exception>
public static void ForEach<T>(this Stack<T> stack, Action<T, int> action)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(action);
var index = 0;
foreach (var item in stack)
{
action(item, index++);
}
}
/// <summary>
/// 创建一个新堆栈,包含满足条件的元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">原堆栈</param>
/// <param name="predicate">筛选条件</param>
/// <returns>包含满足条件元素的新堆栈</returns>
/// <exception cref="ArgumentNullException">堆栈或条件为空时抛出</exception>
public static Stack<T> Where<T>(this Stack<T> stack, Func<T, bool> predicate)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(predicate);
var filteredItems = stack.Where(predicate).ToArray();
return new Stack<T>(filteredItems);
}
/// <summary>
/// 创建一个新堆栈,包含转换后的元素
/// </summary>
/// <typeparam name="TSource">原堆栈元素类型</typeparam>
/// <typeparam name="TResult">目标堆栈元素类型</typeparam>
/// <param name="stack">原堆栈</param>
/// <param name="selector">转换函数</param>
/// <returns>包含转换后元素的新堆栈</returns>
/// <exception cref="ArgumentNullException">堆栈或转换函数为空时抛出</exception>
public static Stack<TResult> Select<TSource, TResult>(this Stack<TSource> stack, Func<TSource, TResult> selector)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(selector);
var transformedItems = stack.Select(selector).ToArray();
return new Stack<TResult>(transformedItems);
}
/// <summary>
/// 反转堆栈中的元素顺序
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
public static void Reverse<T>(this Stack<T> stack)
{
ArgumentNullException.ThrowIfNull(stack);
if (stack.Count <= 1)
{
return;
}
var items = new T[stack.Count];
var index = 0;
while (stack.Count > 0)
{
items[index++] = stack.Pop();
}
foreach (var item in items)
{
stack.Push(item);
}
}
/// <summary>
/// 获取堆栈的深度副本(递归反转以保持原始顺序)
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">原堆栈</param>
/// <returns>深度副本的新堆栈</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
public static Stack<T> DeepClone<T>(this Stack<T> stack)
{
ArgumentNullException.ThrowIfNull(stack);
var tempStack = new Stack<T>();
var result = new Stack<T>();
// 第一次反转到临时堆栈
foreach (var item in stack)
{
tempStack.Push(item);
}
// 第二次反转到结果堆栈,恢复原始顺序
while (tempStack.Count > 0)
{
result.Push(tempStack.Pop());
}
return result;
}
/// <summary>
/// 限制堆栈的最大长度,超出时移除底部元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="maxSize">最大长度</param>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
/// <exception cref="ArgumentOutOfRangeException">最大长度小于0时抛出</exception>
public static void LimitSize<T>(this Stack<T> stack, int maxSize)
{
ArgumentNullException.ThrowIfNull(stack);
if (maxSize < 0)
{
throw new ArgumentOutOfRangeException(nameof(maxSize), "最大长度不能小于0");
}
if (stack.Count <= maxSize)
{
return;
}
// 将堆栈内容转移到数组保留最新的maxSize个元素
var items = stack.ToArray();
stack.Clear();
// 重新入栈最新的maxSize个元素
for (var i = Math.Min(maxSize - 1, items.Length - 1); i >= 0; i--)
{
stack.Push(items[i]);
}
}
/// <summary>
/// 安全地入栈元素,如果堆栈已满则移除底部元素
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="item">要入栈的元素</param>
/// <param name="maxSize">堆栈最大长度</param>
/// <returns>被移除的元素(如果有)</returns>
/// <exception cref="ArgumentNullException">堆栈为空时抛出</exception>
/// <exception cref="ArgumentOutOfRangeException">最大长度小于1时抛出</exception>
public static T? PushWithLimit<T>(this Stack<T> stack, T item, int maxSize)
{
ArgumentNullException.ThrowIfNull(stack);
if (maxSize < 1)
{
throw new ArgumentOutOfRangeException(nameof(maxSize), "最大长度不能小于1");
}
T? removedItem = default;
if (stack.Count >= maxSize)
{
// 将所有元素转移到数组
var items = stack.ToArray();
stack.Clear();
// 保存被移除的底部元素
if (items.Length > 0)
{
removedItem = items[items.Length - 1];
}
// 重新入栈,跳过底部元素
for (var i = Math.Min(maxSize - 2, items.Length - 2); i >= 0; i--)
{
stack.Push(items[i]);
}
}
stack.Push(item);
return removedItem;
}
/// <summary>
/// 检查是否所有元素都满足条件
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="predicate">匹配条件</param>
/// <returns>是否所有元素都满足条件</returns>
/// <exception cref="ArgumentNullException">堆栈或条件为空时抛出</exception>
public static bool All<T>(this Stack<T> stack, Func<T, bool> predicate)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(predicate);
return stack.All(predicate);
}
/// <summary>
/// 检查是否至少有一个元素满足条件
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="stack">堆栈实例</param>
/// <param name="predicate">匹配条件</param>
/// <returns>是否至少有一个元素满足条件</returns>
/// <exception cref="ArgumentNullException">堆栈或条件为空时抛出</exception>
public static bool Any<T>(this Stack<T> stack, Func<T, bool> predicate)
{
ArgumentNullException.ThrowIfNull(stack);
ArgumentNullException.ThrowIfNull(predicate);
return stack.Any(predicate);
}
/// <summary>
/// 合并两个堆栈(第二个堆栈的元素将位于顶部)
/// </summary>
/// <typeparam name="T">堆栈元素类型</typeparam>
/// <param name="first">第一个堆栈</param>
/// <param name="second">第二个堆栈</param>
/// <returns>合并后的新堆栈</returns>
/// <exception cref="ArgumentNullException">任一堆栈为空时抛出</exception>
public static Stack<T> Concat<T>(this Stack<T> first, Stack<T> second)
{
ArgumentNullException.ThrowIfNull(first);
ArgumentNullException.ThrowIfNull(second);
var result = new Stack<T>();
// 先添加第一个堆栈的元素(从底部到顶部)
var firstItems = first.ToArray();
for (var i = firstItems.Length - 1; i >= 0; i--)
{
result.Push(firstItems[i]);
}
// 再添加第二个堆栈的元素(从底部到顶部)
var secondItems = second.ToArray();
for (var i = secondItems.Length - 1; i >= 0; i--)
{
result.Push(secondItems[i]);
}
return result;
}
}