This repository has been archived on 2025-09-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
XericLibrary-OLD/Runtime/MicroLibrary/MacroList.cs

171 lines
4.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Codice.CM.Triggers;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;
namespace XericLibrary.Runtime.MacroLibrary
{
public static partial class MacroMath
{
#region
/// <summary>
/// Fisher-Yates洗牌算法时间复杂度为O(n*n),空间复杂度为O(n);
/// 缺点是元素0很大概率会在最后出现
/// </summary>
/// <param name="length">待选项目的索引长度</param>
/// <param name="select">输出项目的索引长度</param>
/// <returns></returns>
public static List<int> FisherYatesShuffle(int length, int select)
{
if(select > length)
throw new ArgumentOutOfRangeException("在进行洗牌时,要求输出的项目比拥有的项目更多,这是不合理的。");
var random = new System.Random();
List<int> arr = Enumerable.Range(0, length).ToList();
List<int> res = new List<int>();
for(int i = 0; i < select; ++i)
{
int k = random.Next(arr.Count);
res.Add(arr[k]);
arr.RemoveAt(k);
}
return res;
}
/// <summary>
/// 重复的洗牌
/// </summary>
/// <param name="length"></param>
/// <param name="select"></param>
/// <param name="repet"></param>
/// <returns></returns>
public static List<int> FisherYatesShuffle(int length, int select, int repet)
{
if(select > length)
throw new ArgumentOutOfRangeException("在进行洗牌时,要求输出的项目比拥有的项目更多,这是不合理的。");
#if UNITY_EDITOR
if(repet > 100)
Debug.LogError("洗牌的重复次数太高(> 100),已限制数量");
#endif
repet = Math.Clamp(repet, 1, 100);
var random = new System.Random();
List<int> arr = Enumerable.Range(0, length).ToList();
List<int> res = new List<int>();
for(int j = 0; j < repet; j++)
{
for(int i = 0; i < length; i++)
{
int k = random.Next(arr.Count);
res.Add(arr[k]);
arr.RemoveAt(k);
}
arr = res.ToList();
res.Clear();
}
return arr;
}
/// <summary>
/// 蓄水池抽样算法,可以在线程安全的情况下完成洗牌。
/// </summary>
/// <param name="arr"></param>
/// <param name="select">需要抽取的样本 M</param>
/// <param name="reservoir"></param>
/// <param name="cancellationToken"></param>
public static void ReservoirSampling(List<int> arr, int select, ConcurrentBag<int> reservoir, CancellationToken cancellationToken)
{
/**
* int M = 3; // 需要抽样的元素个数
* int totalElements = 10; // 输入数据的总元素个数
* var arr = new List<int>();
*
* for (int i = 1; i <= totalElements; i++)
* {
* arr.Add(i);
* }
*
* ConcurrentBag<int> reservoir = new ConcurrentBag<int>();
* Random random = new Random();
*
* var cancellationTokenSource = new CancellationTokenSource();
* var cancellationToken = cancellationTokenSource.Token;
*
* ThreadPool.QueueUserWorkItem(state =>
* ReservoirSampling(arr, M, reservoir, random, cancellationToken);
* , null);
*
* // 停止抽样
* cancellationTokenSource.Cancel();
*/
var random = new System.Random();
for(int i = select; i < arr.Count; ++i)
{
if(cancellationToken.IsCancellationRequested)
return;
int k = random.Next(i + 1); // 生成一个随机数 k范围是 [0, i]
if(k < select)
{
// 如果 k 小于 M将 arr[k] 添加到抽样结果中
reservoir.Add(arr[k]);
}
}
}
#endregion
#region
/// <summary>
/// 获取列表中随机顺序的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="count">需要采样的数量</param>
/// <returns></returns>
public static IEnumerable<T> GetRandom<T>(this List<T> list, int count = -1)
{
var index = FisherYatesShuffle(list.Count, count <= 0 ? list.Count : count);
for(int i = 0; i < index.Count; i++)
yield return list[index[i]];
}
/// <summary>
/// 对列表中的成员按组进行划分,并读取特定组中特定索引下的成员
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="group"></param>
/// <param name="target"></param>
/// <returns></returns>
public static IEnumerable<T> GetListGroupMember<T>(this List<T> list, int group, int target)
{
if(list.Count % group != 0)
throw new Exception("在进行列组成员获取时,组不能刚好整除列表总数");
for(int i = 0; i < list.Count; i++)
if((i % group) == target)
yield return list[i];
}
#endregion
}
}