Extension.Enumerable.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using TBL.CSharp.Utilities.Random;
  5. namespace TBL.CSharp.Base
  6. {
  7. public static partial class Extension
  8. {
  9. /// <summary>
  10. /// 拓扑排序
  11. /// </summary>
  12. /// <param name="source">要排序的原始集合</param>
  13. /// <param name="getDependencies">每个项获得依赖项的方法</param>
  14. /// <param name="sortedElements">存储已排序元素的列表</param>
  15. /// <param name="visitedElements">存储已访问元素的映射表</param>
  16. /// <typeparam name="T">要排序的元素类型</typeparam>
  17. /// <returns>排序后的结果</returns>
  18. /// <exception cref="ArgumentException">无法完成拓扑排序</exception>
  19. public static IList<T> TopologicalSort<T>(
  20. this IEnumerable<T> source,
  21. Func<T, IEnumerable<T>> getDependencies,
  22. IList<T> sortedElements,
  23. IDictionary<T, bool> visitedElements
  24. )
  25. {
  26. void Visit(T item, Func<T, IEnumerable<T>> dependenciesProvider,
  27. ICollection<T> sorted, IDictionary<T, bool> visited)
  28. {
  29. if (item == null)
  30. return;
  31. var alreadyVisited = visited.TryGetValue(item, out var inProcess);
  32. if (alreadyVisited)
  33. {
  34. if (inProcess)
  35. {
  36. throw new ArgumentException("Cyclic dependency found.");
  37. }
  38. }
  39. else
  40. {
  41. visited[item] = true;
  42. var dependencies = dependenciesProvider(item);
  43. if (dependencies != null)
  44. {
  45. foreach (var dependency in dependencies)
  46. {
  47. Visit(dependency, dependenciesProvider, sorted, visited);
  48. }
  49. }
  50. visited[item] = false;
  51. sorted.Add(item);
  52. }
  53. }
  54. sortedElements.Clear();
  55. visitedElements.Clear();
  56. foreach (var item in source)
  57. {
  58. Visit(item, getDependencies, sortedElements, visitedElements);
  59. }
  60. return sortedElements;
  61. }
  62. /// <summary>
  63. /// 用默认临时对象进行拓扑排序
  64. /// </summary>
  65. /// <param name="source">要排序的原始集合</param>
  66. /// <param name="getDependencies">每个项获得依赖项的方法</param>
  67. /// <typeparam name="T">要排序的元素类型</typeparam>
  68. /// <returns>排序后的结果</returns>
  69. /// <exception cref="ArgumentException">无法完成拓扑排序</exception>
  70. public static IList<T> TopologicalSort<T>(
  71. this IEnumerable<T> source,
  72. Func<T, IEnumerable<T>> getDependencies
  73. ) =>
  74. TopologicalSort(source, getDependencies, new List<T>(), new Dictionary<T, bool>());
  75. /// <summary>
  76. /// 生成元素排列字符串
  77. /// </summary>
  78. public static string VisitElements<T>(
  79. this IEnumerable<T> source,
  80. StringBuilder stringBuilder,
  81. string separator = ", ",
  82. bool withInitialClear = true
  83. )
  84. {
  85. if (withInitialClear)
  86. stringBuilder.Clear();
  87. var i = 0;
  88. foreach (var element in source)
  89. {
  90. if (i != 0)
  91. stringBuilder.Append(separator);
  92. stringBuilder.Append(element);
  93. i += 1;
  94. }
  95. return stringBuilder.ToString();
  96. }
  97. /// <summary>
  98. /// 生成元素排列字符串
  99. /// </summary>
  100. public static string VisitElements<T>(
  101. this IEnumerable<T> source, string separator = ", "
  102. )
  103. {
  104. var result = string.Empty;
  105. var i = 0;
  106. foreach (var element in source)
  107. {
  108. if (i != 0)
  109. result += separator;
  110. result += element.ToString();
  111. i += 1;
  112. }
  113. return result;
  114. }
  115. /// <summary>
  116. /// 对传入列表进行洗牌操作
  117. /// <para>算法来源 <see href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle"/></para>
  118. /// </summary>
  119. public static void Shuffle<T>(IRandom random, IList<T> list)
  120. {
  121. for (var i = list.Count - 1; i > 0; --i)
  122. {
  123. var swapIndex = random.Next(i + 1);
  124. (list[swapIndex], list[i]) = (list[i], list[swapIndex]);
  125. }
  126. }
  127. /// <summary>
  128. /// 对传入非托管序列进行洗牌操作
  129. /// <para>算法来源 <see href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle"/></para>
  130. /// </summary>
  131. public static unsafe void Shuffle<T>(IRandom random, T* data, int count) where T : unmanaged
  132. {
  133. for (var i = count - 1; i > 0; --i)
  134. {
  135. var swapIndex = random.Next(i + 1);
  136. (data[swapIndex], data[i]) = (data[i], data[swapIndex]);
  137. }
  138. }
  139. /// <summary>
  140. /// 随机从列表中采取样本
  141. /// </summary>
  142. public static T Sample<T>(IRandom random, IList<T> list) => list[random.Next(list.Count)];
  143. /// <summary>
  144. /// 随机从非托管序列中采取样本
  145. /// </summary>
  146. public static unsafe T Sample<T>(IRandom random, T* data, int count) where T : unmanaged
  147. => data[random.Next(count)];
  148. }
  149. }