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
LiRuoChen 3b8bf5a940 移除了影响打包的部分;
修正了洗牌算法中的错误;
将弱类型中历史记录的功能拆开了,减小了不必要的消耗;
2023-11-01 16:31:58 +08:00

110 lines
2.8 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 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)
/// </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="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]];
}
#endregion
}
}