Guest User

Untitled

a guest
Jan 24th, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.30 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Runtime.CompilerServices;
  6.  
  7. namespace WpfPermutations
  8. {
  9. /// <summary>
  10. /// EO: 2016-04-14
  11. /// Generator of all permutations of an array of anything.
  12. /// Base on Heap's Algorithm. See: https://en.wikipedia.org/wiki/Heap%27s_algorithm#cite_note-3
  13. /// </summary>
  14. public static class Permutations
  15. {
  16. /// <summary>
  17. /// Heap's algorithm to find all pmermutations. Non recursive, more efficient.
  18. /// </summary>
  19. /// <param name="items">Items to permute in each possible ways</param>
  20. /// <param name="funcExecuteAndTellIfShouldStop"></param>
  21. /// <returns>Return true if cancelled</returns>
  22. public static bool ForAllPermutation<T>(T[] items, Func<T[], bool> funcExecuteAndTellIfShouldStop)
  23. {
  24. int countOfItem = items.Length;
  25.  
  26. if (countOfItem <= 1)
  27. {
  28. return funcExecuteAndTellIfShouldStop(items);
  29. }
  30.  
  31. var indexes = new int[countOfItem];
  32. for (int i = 0; i < countOfItem; i++)
  33. {
  34. indexes[i] = 0;
  35. }
  36.  
  37. if (funcExecuteAndTellIfShouldStop(items))
  38. {
  39. return true;
  40. }
  41.  
  42. for (int i = 1; i < countOfItem;)
  43. {
  44. if (indexes[i] < i)
  45. { // On the web there is an implementation with a multiplication which should be less efficient.
  46. if ((i & 1) == 1) // if (i % 2 == 1) ... more efficient ??? At least the same.
  47. {
  48. Swap(ref items[i], ref items[indexes[i]]);
  49. }
  50. else
  51. {
  52. Swap(ref items[i], ref items[0]);
  53. }
  54.  
  55. if (funcExecuteAndTellIfShouldStop(items))
  56. {
  57. return true;
  58. }
  59.  
  60. indexes[i]++;
  61. i = 1;
  62. }
  63. else
  64. {
  65. indexes[i++] = 0;
  66. }
  67. }
  68.  
  69. return false;
  70. }
  71.  
  72. /// <summary>
  73. /// This function is to show a linq way but is far less efficient
  74. /// From: StackOverflow user: Pengyang : http://stackoverflow.com/questions/756055/listing-all-permutations-of-a-string-integer
  75. /// </summary>
  76. /// <typeparam name="T"></typeparam>
  77. /// <param name="list"></param>
  78. /// <param name="length"></param>
  79. /// <returns></returns>
  80. static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
  81. {
  82. if (length == 1) return list.Select(t => new T[] { t });
  83.  
  84. return GetPermutations(list, length - 1)
  85. .SelectMany(t => list.Where(e => !t.Contains(e)),
  86. (t1, t2) => t1.Concat(new T[] { t2 }));
  87. }
  88.  
  89. /// <summary>
  90. /// Swap 2 elements of same type
  91. /// </summary>
  92. /// <typeparam name="T"></typeparam>
  93. /// <param name="a"></param>
  94. /// <param name="b"></param>
  95. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  96. static void Swap<T>(ref T a, ref T b)
  97. {
  98. T temp = a;
  99. a = b;
  100. b = temp;
  101. }
  102.  
  103. /// <summary>
  104. /// Func to show how to call. It does a little test for an array of 4 items.
  105. /// </summary>
  106. public static void Test()
  107. {
  108. ForAllPermutation("123".ToCharArray(), (vals) =>
  109. {
  110. Console.WriteLine(String.Join("", vals));
  111. return false;
  112. });
  113.  
  114. int[] values = new int[] { 0, 1, 2, 4 };
  115.  
  116. Console.WriteLine("Ouellet heap's algorithm implementation");
  117. ForAllPermutation(values, (vals) =>
  118. {
  119. Console.WriteLine(String.Join("", vals));
  120. return false;
  121. });
  122.  
  123. Console.WriteLine("Linq algorithm");
  124. foreach (var v in GetPermutations(values, values.Length))
  125. {
  126. Console.WriteLine(String.Join("", v));
  127. }
  128.  
  129. // Performance Heap's against Linq version : huge differences
  130. int count = 0;
  131.  
  132. values = new int[10];
  133. for (int n = 0; n < values.Length; n++)
  134. {
  135. values[n] = n;
  136. }
  137.  
  138. Stopwatch stopWatch = new Stopwatch();
  139.  
  140. ForAllPermutation(values, (vals) =>
  141. {
  142. foreach (var v in vals)
  143. {
  144. count++;
  145. }
  146. return false;
  147. });
  148.  
  149. stopWatch.Stop();
  150. Console.WriteLine($"Ouellet heap's algorithm implementation {count} items in {stopWatch.ElapsedMilliseconds} millisecs");
  151.  
  152. count = 0;
  153. stopWatch.Reset();
  154. stopWatch.Start();
  155.  
  156. foreach (var vals in GetPermutations(values, values.Length))
  157. {
  158. foreach (var v in vals)
  159. {
  160. count++;
  161. }
  162. }
  163.  
  164. stopWatch.Stop();
  165. Console.WriteLine($"Linq {count} items in {stopWatch.ElapsedMilliseconds} millisecs");
  166. }
  167. }
  168. }
  169.  
  170. ForAllPermutation("123".ToCharArray(), (vals) =>
  171. {
  172. Console.WriteLine(String.Join("", vals));
  173. return false;
  174. });
  175.  
  176. int[] values = new int[] { 0, 1, 2, 4 };
  177. ForAllPermutation(values, (vals) =>
  178. {
  179. Console.WriteLine(String.Join("", vals));
  180. return false;
  181. });
  182.  
  183. public static IEnumerable<T[]> Permute<T>(T[] array)
  184. {
  185. for(int i=0; i<array.Length; i++)
  186. {
  187. if (array.Length <= 1)
  188. {
  189. yield return array;
  190. }
  191. else
  192. {
  193. T[] except = new T[array.Length - 1];
  194. Array.Copy(array, except, i);
  195. Array.Copy(array, i + 1, except, i, array.Length - i - 1);
  196. foreach (T[] sub in Permute(except))
  197. {
  198. T[] answer = new T[sub.Length + 1];
  199. Array.Copy(sub, 0, answer, 1, sub.Length);
  200. answer[0] = array[i];
  201. yield return answer;
  202. }
  203. }
  204. }
  205. }
Add Comment
Please, Sign In to add comment