PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ServiceStack.Common/EnumerableExtensions.cs

http://github.com/ServiceStack/ServiceStack
C# | 376 lines | 324 code | 49 blank | 3 comment | 88 complexity | 2ded7d9064281e42b6f465be32080f3a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Runtime.CompilerServices;
  6. namespace ServiceStack
  7. {
  8. public static class EnumerableUtils
  9. {
  10. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  11. public static object FirstOrDefault(IEnumerable items)
  12. {
  13. if (items == null)
  14. return null;
  15. foreach (var item in items)
  16. {
  17. return item;
  18. }
  19. return null;
  20. }
  21. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  22. public static object ElementAt(IEnumerable items, int index)
  23. {
  24. if (items == null)
  25. return null;
  26. var i = 0;
  27. foreach (var item in items)
  28. if (i++ == index)
  29. return item;
  30. return null;
  31. }
  32. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  33. public static List<object> Skip(IEnumerable items, int count)
  34. {
  35. if (items == null)
  36. return TypeConstants.EmptyObjectList;
  37. var to = new List<object>();
  38. int i = 0;
  39. foreach (var item in items)
  40. {
  41. if (count > i++)
  42. continue;
  43. to.Add(item);
  44. }
  45. return to;
  46. }
  47. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  48. public static List<object> SplitOnFirst(IEnumerable items, out object first)
  49. {
  50. first = null;
  51. if (items == null)
  52. return TypeConstants.EmptyObjectList;
  53. var to = new List<object>();
  54. int i = 0;
  55. foreach (var item in items)
  56. {
  57. if (i++ < 1)
  58. {
  59. first = item;
  60. continue;
  61. }
  62. to.Add(item);
  63. }
  64. return to;
  65. }
  66. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  67. public static List<object> Take(IEnumerable items, int count)
  68. {
  69. if (items == null)
  70. return TypeConstants.EmptyObjectList;
  71. var to = new List<object>();
  72. int i = 0;
  73. foreach (var item in items)
  74. {
  75. if (count > i++)
  76. {
  77. to.Add(item);
  78. continue;
  79. }
  80. return to;
  81. }
  82. return to;
  83. }
  84. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  85. public static int Count(IEnumerable items)
  86. {
  87. if (items == null)
  88. return 0;
  89. return items is ICollection c
  90. ? c.Count
  91. : items.Cast<object>().Count();
  92. }
  93. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  94. public static List<object> ToList(IEnumerable items)
  95. {
  96. if (items == null)
  97. return TypeConstants.EmptyObjectList;
  98. var to = new List<object>();
  99. foreach (var item in items)
  100. {
  101. to.Add(item);
  102. }
  103. return to;
  104. }
  105. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  106. public static IEnumerable NullIfEmpty(IEnumerable items)
  107. {
  108. if (items != null)
  109. {
  110. foreach (var item in items)
  111. return items;
  112. }
  113. return null;
  114. }
  115. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  116. public static bool IsEmpty(IEnumerable items) => EnumerableUtils.NullIfEmpty(items) == null;
  117. }
  118. public static class EnumerableExtensions
  119. {
  120. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  121. public static bool IsEmpty<T>(this ICollection<T> collection) => collection == null || collection.Count == 0;
  122. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  123. public static bool IsEmpty<T>(this T[] collection) => collection == null || collection.Length == 0;
  124. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  125. public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items) => new HashSet<T>(items);
  126. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  127. public static void Each<T>(this IEnumerable<T> values, Action<T> action)
  128. {
  129. if (values == null) return;
  130. foreach (var value in values)
  131. {
  132. action(value);
  133. }
  134. }
  135. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  136. public static void Each<T>(this IEnumerable<T> values, Action<int, T> action)
  137. {
  138. if (values == null) return;
  139. var i = 0;
  140. foreach (var value in values)
  141. {
  142. action(i++, value);
  143. }
  144. }
  145. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  146. public static void Each<TKey, TValue>(this IDictionary<TKey, TValue> map, Action<TKey, TValue> action)
  147. {
  148. if (map == null) return;
  149. var keys = map.Keys.ToList();
  150. foreach (var key in keys)
  151. {
  152. action(key, map[key]);
  153. }
  154. }
  155. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  156. public static List<To> Map<To, From>(this IEnumerable<From> items, Func<From, To> converter)
  157. {
  158. if (items == null)
  159. return new List<To>();
  160. var list = new List<To>();
  161. foreach (var item in items)
  162. {
  163. list.Add(converter(item));
  164. }
  165. return list;
  166. }
  167. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  168. public static List<To> Map<To>(this System.Collections.IEnumerable items, Func<object, To> converter)
  169. {
  170. if (items == null)
  171. return new List<To>();
  172. var list = new List<To>();
  173. foreach (var item in items)
  174. {
  175. list.Add(converter(item));
  176. }
  177. return list;
  178. }
  179. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  180. public static List<object> ToObjects<T>(this IEnumerable<T> items)
  181. {
  182. var to = new List<object>();
  183. foreach (var item in items)
  184. {
  185. to.Add(item);
  186. }
  187. return to;
  188. }
  189. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  190. public static string FirstNonDefaultOrEmpty(this IEnumerable<string> values)
  191. {
  192. foreach (var value in values)
  193. {
  194. if (!string.IsNullOrEmpty(value)) return value;
  195. }
  196. return null;
  197. }
  198. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  199. public static T FirstNonDefault<T>(this IEnumerable<T> values)
  200. {
  201. foreach (var value in values)
  202. {
  203. if (!Equals(value, default(T))) return value;
  204. }
  205. return default(T);
  206. }
  207. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  208. public static bool EquivalentTo(this byte[] bytes, byte[] other)
  209. {
  210. var compare = 0;
  211. for (var i = 0; i < other.Length; i++)
  212. compare |= other[i] ^ bytes[i];
  213. return compare == 0;
  214. }
  215. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  216. public static bool EquivalentTo<T>(this T[] array, T[] otherArray, Func<T, T, bool> comparer = null)
  217. {
  218. if (array == null || otherArray == null)
  219. return array == otherArray;
  220. if (array.Length != otherArray.Length)
  221. return false;
  222. if (comparer == null)
  223. comparer = (v1, v2) => v1.Equals(v2);
  224. for (var i = 0; i < array.Length; i++)
  225. {
  226. if (!comparer(array[i], otherArray[i]))
  227. return false;
  228. }
  229. return true;
  230. }
  231. public static bool EquivalentTo<T>(this IEnumerable<T> thisList, IEnumerable<T> otherList, Func<T, T, bool> comparer = null)
  232. {
  233. if (comparer == null)
  234. comparer = (v1, v2) => v1.Equals(v2);
  235. if (thisList == null || otherList == null)
  236. return thisList == otherList;
  237. var otherEnum = otherList.GetEnumerator();
  238. foreach (var item in thisList)
  239. {
  240. if (!otherEnum.MoveNext()) return false;
  241. var thisIsDefault = Equals(item, default(T));
  242. var otherIsDefault = Equals(otherEnum.Current, default(T));
  243. if (thisIsDefault || otherIsDefault)
  244. {
  245. return thisIsDefault && otherIsDefault;
  246. }
  247. if (!comparer(item, otherEnum.Current)) return false;
  248. }
  249. var hasNoMoreLeftAsWell = !otherEnum.MoveNext();
  250. return hasNoMoreLeftAsWell;
  251. }
  252. public static bool EquivalentTo<K, V>(this IDictionary<K, V> a, IDictionary<K, V> b, Func<V,V,bool> comparer = null)
  253. {
  254. if (comparer == null)
  255. comparer = (v1, v2) => v1.Equals(v2);
  256. if (a == null || b == null)
  257. return a == b;
  258. if (a.Count != b.Count)
  259. return false;
  260. foreach (var entry in a)
  261. {
  262. V value;
  263. if (!b.TryGetValue(entry.Key, out value))
  264. return false;
  265. if (entry.Value == null || value == null)
  266. {
  267. if (entry.Value == null && value == null)
  268. continue;
  269. return false;
  270. }
  271. if (!comparer(entry.Value, value))
  272. return false;
  273. }
  274. return true;
  275. }
  276. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  277. public static IEnumerable<T[]> BatchesOf<T>(this IEnumerable<T> sequence, int batchSize)
  278. {
  279. var batch = new List<T>(batchSize);
  280. foreach (var item in sequence)
  281. {
  282. batch.Add(item);
  283. if (batch.Count >= batchSize)
  284. {
  285. yield return batch.ToArray();
  286. batch.Clear();
  287. }
  288. }
  289. if (batch.Count > 0)
  290. {
  291. yield return batch.ToArray();
  292. batch.Clear();
  293. }
  294. }
  295. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  296. public static Dictionary<TKey, T> ToSafeDictionary<T, TKey>(this IEnumerable<T> list, Func<T, TKey> expr)
  297. {
  298. var map = new Dictionary<TKey, T>();
  299. if (list != null)
  300. {
  301. foreach (var item in list)
  302. {
  303. map[expr(item)] = item;
  304. }
  305. }
  306. return map;
  307. }
  308. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  309. public static Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(this IEnumerable<T> list, Func<T, KeyValuePair<TKey, TValue>> map)
  310. {
  311. var to = new Dictionary<TKey, TValue>();
  312. foreach (var item in list)
  313. {
  314. var entry = map(item);
  315. to[entry.Key] = entry.Value;
  316. }
  317. return to;
  318. }
  319. /// <summary>
  320. /// Return T[0] when enumerable is null, safe to use in enumerations like foreach
  321. /// </summary>
  322. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  323. public static IEnumerable<T> Safe<T>(this IEnumerable<T> enumerable) => enumerable ?? TypeConstants<T>.EmptyArray;
  324. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  325. public static IEnumerable Safe(this IEnumerable enumerable) => enumerable ?? TypeConstants.EmptyObjectArray;
  326. }
  327. }