/Source/LoreSoft.Shared/Extensions/EnumerableExtensions.cs

https://github.com/loresoft/LoreSoft.Shared · C# · 279 lines · 181 code · 44 blank · 54 comment · 24 complexity · 45ecf67f4a0fe27d761d9ff4d8c0bdb8 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Linq;
  5. using System.Text;
  6. namespace LoreSoft.Shared.Extensions
  7. {
  8. public static class EnumerableExtensions
  9. {
  10. public static bool Contains<TSource>(this IEnumerable<TSource> enumerable, Func<TSource, bool> function)
  11. {
  12. var a = enumerable.FirstOrDefault(function);
  13. var b = default(TSource);
  14. return !Equals(a, b);
  15. }
  16. public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  17. {
  18. return source.DistinctBy(keySelector, EqualityComparer<TKey>.Default);
  19. }
  20. public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  21. {
  22. if (source == null)
  23. throw new ArgumentNullException("source");
  24. if (keySelector == null)
  25. throw new ArgumentNullException("keySelector");
  26. if (comparer == null)
  27. throw new ArgumentNullException("comparer");
  28. return DistinctByImpl(source, keySelector, comparer);
  29. }
  30. private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  31. {
  32. var knownKeys = new HashSet<TKey>(comparer);
  33. foreach (var element in source)
  34. if (knownKeys.Add(keySelector(element)))
  35. yield return element;
  36. }
  37. public static void AddRange<TSource>(this ICollection<TSource> list, IEnumerable<TSource> range)
  38. {
  39. foreach (var r in range)
  40. list.Add(r);
  41. }
  42. public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
  43. {
  44. foreach (var item in source)
  45. action(item);
  46. }
  47. public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> items)
  48. {
  49. return items == null || !items.Any();
  50. }
  51. public static int IndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> selector)
  52. {
  53. int index = 0;
  54. foreach (var item in source)
  55. {
  56. if (selector(item))
  57. return index;
  58. index++;
  59. }
  60. // not found
  61. return -1;
  62. }
  63. private static readonly Random _random = new Random();
  64. public static TSource Random<TSource>(this IEnumerable<TSource> items)
  65. {
  66. if (items == null)
  67. throw new ArgumentNullException("items");
  68. int count = items.Count();
  69. if (count == 0)
  70. return default(TSource);
  71. int index = _random.Next(0, count);
  72. return items.ElementAt(index);
  73. }
  74. public static TSource Random<TSource>(this IEnumerable<TSource> items, Func<TSource, int> weightSelector)
  75. {
  76. if (items == null)
  77. throw new ArgumentNullException("items");
  78. // if no weight delegate, use standard random
  79. if (weightSelector == null)
  80. return items.Random();
  81. // total weight
  82. int total = items.Sum(weightSelector);
  83. if (total == 0)
  84. return default(TSource);
  85. // random index between 0 and total weight
  86. int index = _random.Next(0, total);
  87. int lastWeight = 0;
  88. // each item is given a range based on weight
  89. foreach (var item in items)
  90. {
  91. int weight = weightSelector(item);
  92. int start = lastWeight;
  93. int end = lastWeight + weight;
  94. // if index is between last weight and this weight, return
  95. if (index.Between(start, end))
  96. return item;
  97. lastWeight = end;
  98. }
  99. // shouldn't reach here
  100. return items.FirstOrDefault();
  101. }
  102. /// <summary>
  103. /// Converts an IEnumerable of values to a delimited string.
  104. /// </summary>
  105. /// <typeparam name="T">
  106. /// The type of objects to delimit.
  107. /// </typeparam>
  108. /// <param name="values">
  109. /// The IEnumerable string values to convert.
  110. /// </param>
  111. /// <param name="delimiter">
  112. /// The delimiter.
  113. /// </param>
  114. /// <returns>
  115. /// A delimited string of the values.
  116. /// </returns>
  117. public static string ToDelimitedString<T>(this IEnumerable<T> values, string delimiter)
  118. {
  119. var sb = new StringBuilder();
  120. foreach (var i in values)
  121. {
  122. if (sb.Length > 0)
  123. sb.Append(delimiter);
  124. sb.Append(i.ToString());
  125. }
  126. return sb.ToString();
  127. }
  128. /// <summary>
  129. /// Converts an IEnumerable of values to a delimited string.
  130. /// </summary>
  131. /// <param name="values">The IEnumerable string values to convert.</param>
  132. /// <returns>A delimited string of the values.</returns>
  133. public static string ToDelimitedString(this IEnumerable<string> values)
  134. {
  135. return ToDelimitedString(values, ",");
  136. }
  137. /// <summary>
  138. /// Converts an IEnumerable of values to a delimited string.
  139. /// </summary>
  140. /// <param name="values">The IEnumerable string values to convert.</param>
  141. /// <param name="delimiter">The delimiter.</param>
  142. /// <returns>A delimited string of the values.</returns>
  143. public static string ToDelimitedString(this IEnumerable<string> values, string delimiter)
  144. {
  145. var sb = new StringBuilder();
  146. foreach (var i in values)
  147. {
  148. if (sb.Length > 0)
  149. sb.Append(delimiter);
  150. sb.Append(i);
  151. }
  152. return sb.ToString();
  153. }
  154. /// <summary>
  155. /// Creates a <see cref="T:System.Collections.Generic.HashSet`1"/> from an <see cref="T:System.Collections.Generic.IEnumerable`1"/>.
  156. /// </summary>
  157. /// <typeparam name="T">The type of the elements of source.</typeparam>
  158. /// <param name="source">The <see cref="T:System.Collections.Generic.IEnumerable`1"/> to create a <see cref="T:System.Collections.Generic.HashSet`1"/> from.</param>
  159. /// <returns>A <see cref="T:System.Collections.Generic.HashSet`1"/> that contains elements from the input sequence.</returns>
  160. public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
  161. {
  162. return new HashSet<T>(source);
  163. }
  164. /// <summary>
  165. /// Creates a <see cref="T:System.Collections.Generic.HashSet`1"/> from an <see cref="T:System.Collections.Generic.IEnumerable`1"/>.
  166. /// </summary>
  167. /// <typeparam name="T">The type of the elements of source.</typeparam>
  168. /// <param name="source">The <see cref="T:System.Collections.Generic.IEnumerable`1"/> to create a <see cref="T:System.Collections.Generic.HashSet`1"/> from.</param>
  169. /// <param name="comparer">An <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> to compare elements.</param>
  170. /// <returns>
  171. /// A <see cref="T:System.Collections.Generic.HashSet`1"/> that contains elements from the input sequence.
  172. /// </returns>
  173. public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer)
  174. {
  175. return new HashSet<T>(source, comparer);
  176. }
  177. public static IEnumerable<IndexedItem<T>> ToIndexed<T>(this IEnumerable<T> items)
  178. {
  179. int index = 0;
  180. return items.Select(item => new IndexedItem<T>(index++, item));
  181. }
  182. public static IEnumerable<Node<T>> ToTree<T>(this IEnumerable<T> collection, Func<T, T> getParent)
  183. where T : class
  184. {
  185. var top = new Node<T>();
  186. var dic = new Dictionary<T, Node<T>>();
  187. Func<T, Node<T>> createNode = null;
  188. createNode = item => dic.GetOrAdd(item, k =>
  189. {
  190. var itemNode = new Node<T>(item);
  191. T parent = getParent(item);
  192. var parentNode = parent != null ? createNode(parent) : top;
  193. parentNode.Children.Add(itemNode);
  194. return itemNode;
  195. });
  196. foreach (var item in collection)
  197. createNode(item);
  198. return top.Children;
  199. }
  200. /// <summary>
  201. /// Creates a <see cref="T:System.Collections.ObjectModel.ObservableCollection`1"/> from an <see cref="T:System.Collections.Generic.IEnumerable`1"/>.
  202. /// </summary>
  203. /// <typeparam name="T">The type of the elements of source.</typeparam>
  204. /// <param name="source">The <see cref="T:System.Collections.Generic.IEnumerable`1"/> to create a <see cref="T:System.Collections.ObjectModel.ObservableCollection`1"/> from.</param>
  205. /// <returns>A <see cref="T:System.Collections.ObjectModel.ObservableCollection`1"/> that contains elements from the input sequence.</returns>
  206. public static ObservableCollection<T> ToObservable<T>(this IEnumerable<T> source)
  207. {
  208. return new ObservableCollection<T>(source);
  209. }
  210. }
  211. public class IndexedItem<T>
  212. {
  213. public IndexedItem(int index, T item)
  214. {
  215. Index = index;
  216. Item = item;
  217. }
  218. public int Index { get; private set; }
  219. public T Item { get; private set; }
  220. }
  221. public class Node<T>
  222. {
  223. public T Value { get; set; }
  224. public List<Node<T>> Children { get; set; }
  225. public Node(T value)
  226. {
  227. Value = value;
  228. Children = new List<Node<T>>();
  229. }
  230. public Node()
  231. {
  232. Children = new List<Node<T>>();
  233. }
  234. }
  235. }