PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Helpers/ArrayHelper.cs

#
C# | 1690 lines | 1028 code | 116 blank | 546 comment | 152 complexity | 16ca740437cf6fdf9e0a239565ae6d1b MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text;
  6. using NUnit.Framework;
  7. namespace Delta.Utilities.Helpers
  8. {
  9. /// <summary>
  10. /// Array helper class adding extra functionality to the System.Array class
  11. /// and similar classes (lists). Most useful methods here are resizing
  12. /// arrays, building sub arrays and adding arrays together.
  13. /// </summary>
  14. public static class ArrayHelper
  15. {
  16. #region Delegates
  17. /// <summary>
  18. /// Parameterless delegate for code that should be invoked by the
  19. /// FreeDataWhenMemoryIsLow event handler.
  20. /// </summary>
  21. public delegate void FreeMemoryDelegate();
  22. #endregion
  23. #region GetSubArray (Static)
  24. /// <summary>
  25. /// Get sub array (similar to String.Substring), again there is no function
  26. /// for arrays to do that easily.
  27. /// </summary>
  28. /// <typeparam name="T">Type of array</typeparam>
  29. /// <param name="length">
  30. /// Length of data to copy (can be smaller than originalData array size)
  31. /// </param>
  32. /// <param name="originalData">Data to grab from (full array)</param>
  33. /// <param name="startIndex">Start index for originalData</param>
  34. /// <returns>New array of type T with the specified length</returns>
  35. /// <exception cref="ArgumentOutOfRangeException">
  36. /// <c>startIndex</c> is out of range.
  37. /// </exception>
  38. public static T[] GetSubArray<T>(
  39. this T[] originalData, int startIndex, int length)
  40. {
  41. if (startIndex > originalData.Length)
  42. {
  43. throw new ArgumentOutOfRangeException("startIndex",
  44. "Must be smaller than originalData.Length=" + originalData.Length);
  45. }
  46. if (length > startIndex + originalData.Length)
  47. {
  48. throw new ArgumentOutOfRangeException("length",
  49. "Must be smaller than startIndex=" + startIndex +
  50. "+originalData.Length=" + originalData.Length);
  51. }
  52. T[] ret = new T[length];
  53. Array.Copy(originalData, startIndex, ret, 0, length);
  54. return ret;
  55. }
  56. /// <summary>
  57. /// Get sub array (similar to String.Substring), again there is no function
  58. /// for arrays to do that easily.
  59. /// </summary>
  60. /// <typeparam name="T">Type of array</typeparam>
  61. /// <param name="originalData">Original Data</param>
  62. /// <param name="startIndex">Start Index</param>
  63. public static T[] GetSubArray<T>(this T[] originalData, int startIndex)
  64. {
  65. return GetSubArray(originalData, startIndex,
  66. originalData.Length - startIndex);
  67. }
  68. #endregion
  69. #region Resize (Static)
  70. /// <summary>
  71. /// Resize array, will create a new array with specified size, then copy
  72. /// all data (with Array.Copy, which is fast) and return the new array.
  73. /// There is no other faster possibility for managed arrays in C#!
  74. /// </summary>
  75. /// <param name="sourceArray">Source array to grab data from, can be
  76. /// bigger or smaller.</param>
  77. /// <param name="newLength">New length for the array we return here</param>
  78. /// <returns>The reduced or increased array</returns>
  79. public static Array Resize(this Array sourceArray, int newLength)
  80. {
  81. // Construct array of same type
  82. Array newArray = Array.CreateInstance(
  83. sourceArray.GetType().GetElementType(),
  84. newLength);
  85. // Copy data
  86. Array.Copy(sourceArray, 0, newArray, 0,
  87. // Don't copy more than any of these 2 arrays can handle!
  88. Math.Min(sourceArray.Length, newArray.Length));
  89. // Return resized array
  90. return newArray;
  91. }
  92. /// <summary>
  93. /// If you need to resize a generic list into another generic list,
  94. /// use Resize. But Resize is slow, the generation of the new list
  95. /// takes some time, use this function to speed that up to 50% faster.
  96. /// It will return a simple array, if this is whats you need you
  97. /// have almost as good as the performance of the normal Resize method.
  98. /// </summary>
  99. /// <typeparam name="T">Type for the sourceArray list</typeparam>
  100. /// <param name="sourceArray">Input</param>
  101. /// <param name="newLength">New desired length for resized array</param>
  102. /// <returns>Resized array, if you need a list, use ResizeSlow</returns>
  103. public static T[] Resize<T>(this List<T> sourceArray, int newLength)
  104. {
  105. // Construct array of same type
  106. T[] newArray = new T[newLength];
  107. // Copy data
  108. sourceArray.CopyTo(0, newArray, 0,
  109. // Don't copy more than any of these 2 arrays can handle!
  110. Math.Min(sourceArray.Count, newArray.Length));
  111. // Return resized array
  112. return newArray;
  113. }
  114. #endregion
  115. #region IsEqualWithoutOrder (Static)
  116. /// <summary>
  117. /// Returns 'true' if both list matches, this means, they have the same
  118. /// elements but the order of the elements doesn't matter.
  119. /// </summary>
  120. /// <typeparam name="T">Type of arrays to compare</typeparam>
  121. /// <param name="list1">List 1</param>
  122. /// <param name="list2">List 2</param>
  123. /// <returns>Returns 'true' if both list matches</returns>
  124. public static bool IsEqualWithoutOrder<T>(this T[] list1, T[] list2)
  125. {
  126. #region Validation check
  127. if (list1 == null || list2 == null ||
  128. list1.Length != list2.Length)
  129. {
  130. return false;
  131. }
  132. #endregion
  133. // Just iterate over all list values
  134. for (int i = 0; i < list1.Length; i++)
  135. {
  136. // and look
  137. bool isNotFound = true;
  138. for (int j = 0; j < list2.Length; j++)
  139. {
  140. // if the current value of the first list exists somewhere at any
  141. // position in the other list
  142. if (list1[i].Equals(list2[j]))
  143. {
  144. // Ok found ^^
  145. isNotFound = false;
  146. break;
  147. }
  148. }
  149. // else if the current value doesn't exist in the other list, then they
  150. // don't match (even by ignoring the ordering)
  151. if (isNotFound)
  152. {
  153. return false;
  154. }
  155. }
  156. // We haven't jumped out yet, so both lists are equal :)
  157. return true;
  158. }
  159. #endregion
  160. #region Compare (Static)
  161. /// <summary>
  162. /// Compare 2 generic Lists. Returns 'true' if both list matches, this
  163. /// means, they have the same elements in the same order.
  164. /// </summary>
  165. /// <typeparam name="T">Type of lists to compare</typeparam>
  166. /// <param name="list1">List 1</param>
  167. /// <param name="list2">List 2</param>
  168. /// <returns>Returns 'true' if both list matches</returns>
  169. public static bool Compare<T>(IList<T> list1, IList<T> list2)
  170. where T : IEquatable<T>
  171. {
  172. // If both lists are exactly equal, we can skip checking
  173. if (list1 == list2)
  174. {
  175. return true;
  176. }
  177. // Validation check
  178. if (list1 == null ||
  179. list2 == null ||
  180. list1.Count != list2.Count)
  181. {
  182. return false;
  183. }
  184. // Go through the whole list and abort if anything is different
  185. for (int num = 0; num < list1.Count; num++)
  186. {
  187. if (list1[num].Equals(list2[num]) == false)
  188. {
  189. return false;
  190. }
  191. }
  192. // Everything was checked, both lists have the same values
  193. return true;
  194. }
  195. /// <summary>
  196. /// Compare 2 arrays, optimized for bytes, which are compared quite often.
  197. /// Returns 'true' if both list matches, this means, they have the same
  198. /// elements in the same order.
  199. /// </summary>
  200. /// <param name="list1">First bytes array</param>
  201. /// <param name="list2">Second bytes array</param>
  202. /// <returns>Returns 'true' if both list matches</returns>
  203. public static bool Compare(byte[] list1, byte[] list2)
  204. {
  205. // If both lists are exactly equal, we can skip checking
  206. if (list1 == list2)
  207. {
  208. return true;
  209. }
  210. // Validation check
  211. if (list1 == null ||
  212. list2 == null ||
  213. list1.Length != list2.Length)
  214. {
  215. return false;
  216. }
  217. // Go through the whole list and abort if anything is different
  218. for (int num = 0; num < list1.Length; num++)
  219. {
  220. if (list1[num] != list2[num])
  221. {
  222. return false;
  223. }
  224. }
  225. // Everything was checked, both lists have the same values
  226. return true;
  227. }
  228. #endregion
  229. #region Add (Static)
  230. /// <summary>
  231. /// Adds 2 arrays, pretty simple, but not implemented in Array!
  232. /// </summary>
  233. /// <param name="array1">Array 1</param>
  234. /// <param name="array2">Array 2</param>
  235. /// <returns>Big new array containing array1 and array2</returns>
  236. public static Array Add(this Array array1, Array array2)
  237. {
  238. // Construct array of same type
  239. Array newArray = Array.CreateInstance(
  240. array1.GetType().GetElementType(),
  241. array1.Length + array2.Length);
  242. // Copy data
  243. Array.Copy(array1, 0, newArray, 0, array1.Length);
  244. Array.Copy(array2, 0, newArray, array1.Length, array2.Length);
  245. // Return new array
  246. return newArray;
  247. }
  248. /// <summary>
  249. /// Adds 2 arrays, pretty simple, but not implemented in Array!
  250. /// </summary>
  251. /// <param name="array1">Array 1</param>
  252. /// <param name="array2">Array 2</param>
  253. /// <returns>Big new array containing array1 and array2</returns>
  254. public static byte[] Add(this byte[] array1, byte[] array2)
  255. {
  256. // Construct array of same type
  257. byte[] newArray = new byte[array1.Length + array2.Length];
  258. // Copy data
  259. Array.Copy(array1, 0, newArray, 0, array1.Length);
  260. Array.Copy(array2, 0, newArray, array1.Length, array2.Length);
  261. // Return new array
  262. return newArray;
  263. }
  264. /// <summary>
  265. /// For generic lists we can simply use .AddRange to do this!
  266. /// Use this method only if you want to create a new list from the
  267. /// first list + all data in the second list.
  268. /// </summary>
  269. /// <typeparam name="T">Type of lists</typeparam>
  270. /// <param name="list1">List 1</param>
  271. /// <param name="list2">List 2</param>
  272. /// <returns>Big new array containing array1 and array2</returns>
  273. public static List<T> Add<T>(this List<T> list1, List<T> list2)
  274. {
  275. List<T> retList = new List<T>(list1);
  276. retList.AddRange(list2);
  277. return retList;
  278. }
  279. #endregion
  280. #region ConvertStringToIntArray (Static)
  281. /// <summary>
  282. /// Convert string data to int array, string must be in the form
  283. /// "1, 3, 8, 7", etc. WriteArrayData is the complementary function.
  284. /// </summary>
  285. /// <param name="text">Input text to be split up, if empty this method
  286. /// will return an empty array.</param>
  287. /// <returns>int array, will be null if string is invalid!</returns>
  288. public static int[] ConvertStringToIntArray(string text)
  289. {
  290. // Invalid?
  291. if (text == null ||
  292. text.Length == 0)
  293. {
  294. return null;
  295. }
  296. string[] splitted = text.Split(new[]
  297. {
  298. ',', ' '
  299. },
  300. StringSplitOptions.RemoveEmptyEntries);
  301. List<int> ret = new List<int>(); //new int[splitted.Length];
  302. for (int i = 0; i < splitted.Length; i++)
  303. {
  304. int newValue;
  305. if (int.TryParse(splitted[i], out newValue))
  306. {
  307. ret.Add(newValue);
  308. }
  309. }
  310. return ret.ToArray();
  311. }
  312. #endregion
  313. #region ConvertByteArrayToIntArray (Static)
  314. /// <summary>
  315. /// Convert byte array to int array, we use 4 bytes and combine them
  316. /// into 1 int (first byte gets shifted 24 bits, next 16, next 8, next 0)
  317. /// </summary>
  318. /// <param name="byteArray">Byte Array</param>
  319. /// <returns>Integer array, has byteArray.Length/4 Length!</returns>
  320. public static int[] ConvertByteArrayToIntArray(byte[] byteArray)
  321. {
  322. // Invalid or too small?
  323. if (byteArray == null ||
  324. byteArray.Length < 4)
  325. {
  326. return null;
  327. }
  328. // 8bit per element to 32bit = /4
  329. int[] ret = new int[byteArray.Length / 4];
  330. for (int i = 0; i < ret.Length; i++)
  331. {
  332. ret[i] =
  333. (byteArray[i * 4 + 0]) +
  334. (byteArray[i * 4 + 1] << 8) +
  335. (byteArray[i * 4 + 2] << 16) +
  336. (byteArray[i * 4 + 3] << 24);
  337. }
  338. return ret;
  339. }
  340. #endregion
  341. #region ConvertIntArrayToByteArray (Static)
  342. /// <summary>
  343. /// Convert int array to byte array, we split each int into 4 bytes
  344. /// (first byte gets shifted 24 bits, next 16, next 8, next 0)
  345. /// </summary>
  346. /// <param name="intArray">Integer array</param>
  347. /// <returns>Byte array, has intArray.Length*4 Length!</returns>
  348. public static byte[] ConvertIntArrayToByteArray(int[] intArray)
  349. {
  350. // Invalid?
  351. if (intArray == null)
  352. {
  353. return null;
  354. }
  355. // 32bit per element to 8bit = *4
  356. byte[] ret = new byte[intArray.Length * 4];
  357. for (int i = 0; i < ret.Length / 4; i++)
  358. {
  359. ret[i * 4 + 0] = (byte)(intArray[i]);
  360. ret[i * 4 + 1] = (byte)(intArray[i] >> 8);
  361. ret[i * 4 + 2] = (byte)(intArray[i] >> 16);
  362. ret[i * 4 + 3] = (byte)(intArray[i] >> 24);
  363. }
  364. return ret;
  365. }
  366. #endregion
  367. #region ConvertByteArrayToString (Static)
  368. /// <summary>
  369. /// Convert a byte array to a string, converts each byte to a char
  370. /// and add them up to the returning string.
  371. /// Useful for generating string data from a byte stream (ANSI style).
  372. /// </summary>
  373. /// <param name="byteArray">Byte array to write from (interpreted as char
  374. /// values)</param>
  375. /// <returns>String with all char values from the byteArray</returns>
  376. public static string ConvertByteArrayToString(byte[] byteArray)
  377. {
  378. if (byteArray == null)
  379. {
  380. return "";
  381. }
  382. StringBuilder ret = new StringBuilder(byteArray.Length);
  383. for (int num = 0; num < byteArray.Length; num++)
  384. {
  385. ret.Append((char)byteArray[num]);
  386. }
  387. return ret.ToString();
  388. }
  389. #endregion
  390. #region ToText (Static)
  391. /// <summary>
  392. /// Converts the list of chars to a string.
  393. /// </summary>
  394. /// <param name="charList">Char list</param>
  395. public static string ToText(this IList<char> charList)
  396. {
  397. if (charList == null)
  398. {
  399. return "";
  400. } // if
  401. // Note: We use here the StringBuilder because its appending of chars is
  402. // 20x faster than by a string
  403. StringBuilder buildString = new StringBuilder(charList.Count);
  404. for (int charId = 0; charId < charList.Count; charId++)
  405. {
  406. buildString.Append(charList[charId]);
  407. }
  408. return buildString.ToString();
  409. }
  410. #endregion
  411. #region RemoveIndex (Static)
  412. /// <summary>
  413. /// Remove a specific array element and return reduced array,
  414. /// often used in ArrayLists, but its more complicated for normal arrays!
  415. /// <para />
  416. /// Note: This method is slower than using dynamic lists.
  417. /// </summary>
  418. /// <typeparam name="T">Type of array data</typeparam>
  419. /// <param name="originalArray">Original Array</param>
  420. /// <param name="index">Index in originalArray</param>
  421. /// <returns>New array with the index removed</returns>
  422. public static T[] RemoveIndex<T>(T[] originalArray, int index)
  423. {
  424. if (index < 0 || originalArray == null ||
  425. index >= originalArray.Length ||
  426. originalArray.Length <= 1)
  427. {
  428. return originalArray;
  429. }
  430. T[] ret = new T[originalArray.Length - 1];
  431. // First part until index
  432. for (int i = 0; i < index; i++)
  433. {
  434. ret[i] = originalArray[i];
  435. }
  436. // Second part from index+1 to end
  437. for (int i = index; i < ret.Length; i++)
  438. {
  439. ret[i] = originalArray[i + 1];
  440. }
  441. return ret;
  442. }
  443. #endregion
  444. #region SetBitInByteArray (Static)
  445. /// <summary>
  446. /// Set bit in byte array
  447. /// </summary>
  448. /// <param name="byteArray">Byte Array</param>
  449. /// <param name="pos">Position to set bit (in bit position)</param>
  450. /// <param name="val">Value to set, either true (1) or false (0)</param>
  451. /// <exception cref="IndexOutOfRangeException">
  452. /// Throws index out of range if the position is more than array.Length*8.
  453. /// </exception>
  454. public static void SetBitInByteArray(
  455. byte[] byteArray, int pos, bool val)
  456. {
  457. int bytePos = pos / 8;
  458. if (bytePos >= byteArray.Length)
  459. {
  460. throw new IndexOutOfRangeException(
  461. "SetBitInByteArray invalid pos=" + pos +
  462. " index, byteArray.Length=" + byteArray.Length);
  463. }
  464. // Set bit at specified place or clear it
  465. if (val)
  466. {
  467. // Just bitwise or with specified bit
  468. byteArray[bytePos] |= (byte)(1 << (pos % 8));
  469. }
  470. else
  471. {
  472. // Create inverted bitmask (only bit position is set to 0)
  473. // then and this with given byte and we have cleared it!
  474. byteArray[bytePos] &= (byte)(~(1 << (pos % 8)));
  475. }
  476. }
  477. #endregion
  478. #region GetBitInByteArray (Static)
  479. /// <summary>
  480. /// Get bit in byte array
  481. /// </summary>
  482. /// <param name="byteArray">Byte Array</param>
  483. /// <param name="pos">Position to set bit (in bit position)</param>
  484. /// <returns>Value to at bit position in byteArray, true (1) or false (0)
  485. /// </returns>
  486. /// <exception cref="IndexOutOfRangeException">
  487. /// Throws index out of range if the position is more than array.Length*8.
  488. /// </exception>
  489. public static bool GetBitInByteArray(
  490. byte[] byteArray, int pos)
  491. {
  492. int bytePos = pos / 8;
  493. if (bytePos >= byteArray.Length)
  494. {
  495. throw new IndexOutOfRangeException(
  496. "SetBitInByteArray invalid pos=" + pos +
  497. " index, byteArray.Length=" + byteArray.Length);
  498. }
  499. // Check if bit is set, we simply shift byte as
  500. // much bit positions as we need and check if value is 1 there!
  501. return (byteArray[bytePos] & (1 << (pos % 8))) != 0;
  502. }
  503. #endregion
  504. #region BuildCompressedByteArrayFromBoolArray (Static)
  505. /// <summary>
  506. /// Creates a byte array from bool array. E.g if bool array has 8 entries
  507. /// we can compress this into one single byte, if it has 21 entries we can
  508. /// use 3 bytes, etc.!
  509. /// </summary>
  510. /// <param name="boolArray">Bool array</param>
  511. /// <returns>Byte array containing all bits from the boolArray</returns>
  512. public static byte[] BuildCompressedByteArrayFromBoolArray(
  513. bool[] boolArray)
  514. {
  515. byte[] byteArray = new byte[1 + ((boolArray.Length - 1) / 8)];
  516. for (int i = 0; i < boolArray.Length; i++)
  517. {
  518. SetBitInByteArray(byteArray, i, boolArray[i]);
  519. }
  520. return byteArray;
  521. }
  522. #endregion
  523. #region FillBoolArrayFromCompressedByteArray (Static)
  524. /// <summary>
  525. /// Rebuilds a bool array compressed with
  526. /// BuildCompressedByteArrayFromBoolArray. E.g. we can extract 8 bool
  527. /// entries from a byte or 14 entries from 2 bytes, etc.
  528. /// </summary>
  529. /// <param name="boolArray">Bool array</param>
  530. /// <param name="byteArray">Byte array, with is 8 times smaller than
  531. /// boolArray</param>
  532. public static void FillBoolArrayFromCompressedByteArray(
  533. bool[] boolArray, byte[] byteArray)
  534. {
  535. for (int i = 0; i < boolArray.Length; i++)
  536. {
  537. boolArray[i] = GetBitInByteArray(byteArray, i);
  538. }
  539. }
  540. #endregion
  541. #region AreCollectionsEqual (Static)
  542. /// <summary>
  543. /// Determines if the two collections contain equal items in the same
  544. /// order. The two collections do not need to be of the same type; it is
  545. /// permissible to compare an array and an OrderedBag, for instance.
  546. /// </summary>
  547. /// <remarks>The default sense of equality for T is used, as defined by T's
  548. /// implementation of IComparable&lt;T&gt;.Equals or object.Equals.
  549. /// </remarks>
  550. /// <typeparam name="T">The type of items in the collections.</typeparam>
  551. /// <param name="collection1">The first collection to compare.</param>
  552. /// <param name="collection2">The second collection to compare.</param>
  553. /// <returns>True if the collections have equal items in the same order.
  554. /// If both collections are empty, true is returned.</returns>
  555. public static bool AreCollectionsEqual<T>(IEnumerable<T> collection1,
  556. IEnumerable<T> collection2)
  557. {
  558. return AreCollectionsEqual(collection1, collection2,
  559. EqualityComparer<T>.Default);
  560. }
  561. /// <summary>
  562. /// Determines if the two collections contain equal items in the same
  563. /// order. The passed instance of IEqualityComparer&lt;T&gt; is used for
  564. /// determining if two items are equal.
  565. /// </summary>
  566. /// <typeparam name="T">The type of items in the collections.</typeparam>
  567. /// <param name="collection1">The first collection to compare.</param>
  568. /// <param name="collection2">The second collection to compare.</param>
  569. /// <param name="equalityComparer">The IEqualityComparer&lt;T&gt; used to
  570. /// compare items for equality.
  571. /// Only the Equals member function of this interface is called.</param>
  572. /// <returns>True if the collections have equal items in the same order.
  573. /// If both collections are empty, true is returned.</returns>
  574. /// <exception cref="ArgumentNullException"><paramref name="collection1"/>,
  575. /// <paramref name="collection2"/>, or <paramref name="equalityComparer"/>
  576. /// is null.</exception>
  577. public static bool AreCollectionsEqual<T>(IEnumerable<T> collection1,
  578. IEnumerable<T> collection2, IEqualityComparer<T> equalityComparer)
  579. {
  580. if (collection1 == null)
  581. {
  582. throw new ArgumentNullException("collection1");
  583. }
  584. if (collection2 == null)
  585. {
  586. throw new ArgumentNullException("collection2");
  587. }
  588. if (equalityComparer == null)
  589. {
  590. throw new ArgumentNullException("equalityComparer");
  591. }
  592. using (IEnumerator<T> enum1 = collection1.GetEnumerator(),
  593. enum2 = collection2.GetEnumerator())
  594. {
  595. bool continue1, continue2;
  596. // Go through all items until done
  597. for (;;)
  598. {
  599. continue1 = enum1.MoveNext();
  600. continue2 = enum2.MoveNext();
  601. if (!continue1 ||
  602. !continue2)
  603. {
  604. break;
  605. }
  606. if (!equalityComparer.Equals(enum1.Current, enum2.Current))
  607. {
  608. // The two items are not equal.
  609. return false;
  610. }
  611. }
  612. // If both continue1 and continue2 are false, we reached the end of
  613. // both sequences at the same time and found success. If one is true
  614. // and one is false, the sequences were of difference lengths->failure.
  615. return (continue1 == continue2);
  616. }
  617. }
  618. #endregion
  619. #region ToArray (Static)
  620. /// <summary>
  621. /// Create an array with the items in a collection.
  622. /// </summary>
  623. /// <remarks>
  624. /// If <paramref name="collection"/> implements ICollection&lt;T&gt;T, then
  625. /// ICollection&lt;T&gt;.CopyTo() is used to fill the array. Otherwise, the
  626. /// IEnumerable&lt;T&gt;.GetEnumerator() is used to fill the array.
  627. /// </remarks>
  628. /// <typeparam name="T">Element type of the collection.</typeparam>
  629. /// <param name="collection">Collection to create array from.</param>
  630. /// <returns>
  631. /// An array with the items from the collection, in enumeration order.
  632. /// </returns>
  633. /// <exception cref="ArgumentNullException">
  634. /// <paramref name="collection"/> is null.
  635. /// </exception>
  636. public static T[] ToArray<T>(IEnumerable<T> collection)
  637. {
  638. if (collection == null)
  639. {
  640. throw new ArgumentNullException("collection");
  641. }
  642. ICollection<T> coll = collection as ICollection<T>;
  643. if (coll != null)
  644. {
  645. // Use ICollection methods to do it more efficiently.
  646. T[] array = new T[coll.Count];
  647. coll.CopyTo(array, 0);
  648. return array;
  649. }
  650. else
  651. {
  652. // We can't allocate the correct size array now, because IEnumerable
  653. // doesn't have a Count property. We could enumerate twice, once to
  654. // count and once to copy. Or we could enumerate once, copying to a
  655. // List, then copy the list to the correct size array. The latter
  656. // algorithm seems more efficient, although it allocates extra memory
  657. // for the list which is then discarded.
  658. List<T> list = new List<T>(collection);
  659. return list.ToArray();
  660. }
  661. }
  662. #endregion
  663. #region Write (Static)
  664. /// <summary>
  665. /// Returns a string with the array data separated with commas.
  666. /// This is the byte array version.
  667. /// </summary>
  668. /// <param name="array">Byte array</param>
  669. /// <returns>A string with the byte array data, comma separated</returns>
  670. public static string Write(this byte[] array)
  671. {
  672. string ret = "";
  673. if (array != null)
  674. {
  675. for (int i = 0; i < array.Length; i++)
  676. {
  677. ret +=
  678. (ret.Length == 0
  679. ? ""
  680. : ", ") + array[i];
  681. }
  682. }
  683. return ret;
  684. }
  685. /// <summary>
  686. /// Returns a string with the array data separated with commas.
  687. /// This is the int array version.
  688. /// </summary>
  689. /// <param name="array">Integer array</param>
  690. /// <returns>A string with the int array data, comma separated</returns>
  691. public static string Write(this int[] array)
  692. {
  693. string ret = "";
  694. if (array != null)
  695. {
  696. for (int i = 0; i < array.Length; i++)
  697. {
  698. ret +=
  699. (ret.Length == 0
  700. ? ""
  701. : ", ") + array[i];
  702. }
  703. }
  704. return ret;
  705. }
  706. /// <summary>
  707. /// Returns a string with the array data separated with commas.
  708. /// This is the general array version.
  709. /// </summary>
  710. /// <param name="array">Array of any type</param>
  711. /// <returns>A string with the array data, comma separated</returns>
  712. public static string Write(this Array array)
  713. {
  714. string ret = "";
  715. if (array != null)
  716. {
  717. for (int i = 0; i < array.Length; i++)
  718. {
  719. ret +=
  720. (ret.Length == 0
  721. ? ""
  722. : ", ") +
  723. (array.GetValue(i) == null
  724. ? "null"
  725. : StringHelper.ToInvariantString(array.GetValue(i)));
  726. }
  727. }
  728. return ret;
  729. }
  730. /// <summary>
  731. /// Returns a string with the array data separated with commas.
  732. /// This is the general array version with maxLength bounding (will return
  733. /// string with max. this number of entries).
  734. /// </summary>
  735. /// <param name="list">List</param>
  736. /// <param name="maxLength">MaxLength</param>
  737. /// <returns>A string with the array data, comma separated</returns>
  738. public static string Write(this Array list, int maxLength)
  739. {
  740. string ret = "";
  741. if (list != null)
  742. {
  743. for (int i = 0; i < list.Length && i < maxLength; i++)
  744. {
  745. ret +=
  746. (ret.Length == 0
  747. ? ""
  748. : ", ") +
  749. StringHelper.ToInvariantString(list.GetValue(i));
  750. }
  751. }
  752. return ret;
  753. }
  754. /// <summary>
  755. /// Returns a string with the array data separated with commas.
  756. /// </summary>
  757. /// <param name="list">List</param>
  758. /// <returns>A string with the array data, comma separated</returns>
  759. public static string Write(this ICollection list)
  760. {
  761. return Write(list, ", ");
  762. }
  763. /// <summary>
  764. /// Returns a string with the array data with given separator.
  765. /// </summary>
  766. /// <param name="list">List to write out</param>
  767. /// <param name="separator">Separator</param>
  768. /// <returns>A string with the array data, comma separated</returns>
  769. public static string Write(this ICollection list, string separator)
  770. {
  771. string ret = "";
  772. if (list != null)
  773. {
  774. foreach (object obj in list)
  775. {
  776. ret +=
  777. (ret.Length == 0
  778. ? ""
  779. : separator) +
  780. StringHelper.ToInvariantString(obj);
  781. }
  782. }
  783. return ret;
  784. }
  785. /// <summary>
  786. /// Returns a string with the array data separated with commas.
  787. /// This is the List&lt;T&gt; version.
  788. /// </summary>
  789. /// <typeparam name="T">Type of list data</typeparam>
  790. /// <param name="list">List to write out</param>
  791. /// <returns>A string with the list data, comma separated</returns>
  792. public static string Write<T>(this List<T> list)
  793. {
  794. string ret = "";
  795. if (list != null)
  796. {
  797. foreach (T obj in list)
  798. {
  799. ret +=
  800. (ret.Length == 0
  801. ? ""
  802. : ", ") +
  803. StringHelper.ToInvariantString(obj);
  804. }
  805. }
  806. return ret;
  807. }
  808. /// <summary>
  809. /// Returns a string with the array data separated with commas.
  810. /// This is the List&lt;T&gt; version with a maximum count.
  811. /// </summary>
  812. /// <typeparam name="T">Type of list data</typeparam>
  813. /// <param name="count">Count</param>
  814. /// <param name="list">List</param>
  815. /// <returns>A string with the list data, comma separated</returns>
  816. public static string Write<T>(this List<T> list, int count)
  817. {
  818. string ret = "";
  819. if (list != null)
  820. {
  821. for (int i = 0; i < list.Count && i < count; i++)
  822. {
  823. ret +=
  824. (ret.Length == 0
  825. ? ""
  826. : ", ") +
  827. StringHelper.ToInvariantString(list[i]);
  828. }
  829. }
  830. return ret;
  831. }
  832. /// <summary>
  833. /// Returns a string with the array data with given separator.
  834. /// This is the List&lt;T&gt; version.
  835. /// </summary>
  836. /// <typeparam name="T">Type of the list data, often strings</typeparam>
  837. /// <param name="list">List to concatenate</param>
  838. /// <param name="separator">Separator used to separate (e.g. comma)</param>
  839. /// <returns>A string with the list data, separator separated</returns>
  840. public static string Write<T>(this List<T> list, string separator)
  841. {
  842. string ret = "";
  843. if (list != null)
  844. {
  845. foreach (T obj in list)
  846. {
  847. ret +=
  848. (ret.Length == 0
  849. ? ""
  850. : separator) +
  851. StringHelper.ToInvariantString(obj);
  852. }
  853. }
  854. return ret;
  855. }
  856. /// <summary>
  857. /// Returns a string with the array data separated with commas.
  858. /// This is the enumerable class version.
  859. /// </summary>
  860. /// <param name="enumerableClass">Enumerable class</param>
  861. /// <returns>A string with the list data, comma separated</returns>
  862. public static string Write(this IEnumerable enumerableClass)
  863. {
  864. return Write(enumerableClass, ", ");
  865. }
  866. /// <summary>
  867. /// Returns a string with the array data separated with commas.
  868. /// This is the enumerable class version.
  869. /// </summary>
  870. /// <param name="enumerableClass">Enumerable class</param>
  871. /// <param name="separator">Separator</param>
  872. /// <returns>A string with the list data, comma separated</returns>
  873. public static string Write(this IEnumerable enumerableClass,
  874. string separator)
  875. {
  876. string ret = "";
  877. if (enumerableClass != null)
  878. {
  879. foreach (object obj in enumerableClass)
  880. {
  881. ret +=
  882. (ret.Length == 0
  883. ? ""
  884. : separator) +
  885. StringHelper.ToInvariantString(obj);
  886. }
  887. }
  888. return ret;
  889. }
  890. #endregion
  891. #region WriteFirstAndLastValues (Static)
  892. /// <summary>
  893. /// Write array data first and last values, e.g. the first 10 and the
  894. /// last 10 values of a really long array (e.g. a network package).
  895. /// All values are separated by commas.
  896. /// <para />
  897. /// Note: If the array has less entries than numberOfItemsAtStartAndEnd
  898. /// times two, we will just display the whole array.
  899. /// </summary>
  900. /// <param name="list">List to grab data from, can be huge</param>
  901. /// <param name="numberOfItemsAtStartAndEnd">Number of items at start and
  902. /// end we want to have in the output string</param>
  903. /// <returns>A string with the list data, comma separated</returns>
  904. public static string WriteFirstAndLastValues(this Array list,
  905. int numberOfItemsAtStartAndEnd)
  906. {
  907. string ret = "";
  908. if (list != null)
  909. {
  910. // If the array has less entries than numberOfItemsAtStartAndEnd * 2,
  911. // display the whole array normally.
  912. if (list.Length <= numberOfItemsAtStartAndEnd * 2)
  913. {
  914. return Write(list);
  915. }
  916. for (int i = 0; i < list.Length && i < numberOfItemsAtStartAndEnd; i++)
  917. {
  918. ret += (ret.Length == 0
  919. ? ""
  920. : ", ") +
  921. StringHelper.ToInvariantString(list.GetValue(i));
  922. }
  923. ret += " ... ";
  924. for (int i = list.Length - numberOfItemsAtStartAndEnd;
  925. i >= 0 && i < list.Length;
  926. i++)
  927. {
  928. ret += (ret.EndsWith(" ... ")
  929. ? ""
  930. : ", ") +
  931. StringHelper.ToInvariantString(list.GetValue(i));
  932. }
  933. }
  934. return ret;
  935. }
  936. #endregion
  937. #region ConcatenateCollections (Static)
  938. /// <summary>
  939. /// Concatenates all the items from several collections. The collections
  940. /// need not be of the same type, but must have the same item type.
  941. /// </summary>
  942. /// <param name="collections">Set of collections to concatenate.
  943. /// In many languages, this parameter can be specified as several
  944. /// individual parameters.</param>
  945. /// <returns>An IEnumerable that enumerates all the items in each of the
  946. /// collections, in order.</returns>
  947. public static IEnumerable<T> ConcatenateCollections<T>(
  948. IEnumerable<T>[] collections)
  949. {
  950. if (collections == null)
  951. {
  952. throw new ArgumentNullException("collections");
  953. }
  954. foreach (IEnumerable<T> coll in collections)
  955. {
  956. foreach (T item in coll)
  957. {
  958. yield return item;
  959. }
  960. }
  961. }
  962. #endregion
  963. #region Count (Static)
  964. /// <summary>
  965. /// Count the number of items in an IEnumerable&lt;T&gt; collection. If
  966. /// a more specific collection type is being used, it is more efficient to
  967. /// use the Count property, if one is provided.
  968. /// </summary>
  969. /// <remarks>If the collection implements ICollection&lt;T&gt;, this method
  970. /// simply returns ICollection&lt;T&gt;.Count. Otherwise, it enumerates all
  971. /// items and counts them.</remarks>
  972. /// <param name="collection">The collection to count items in.</param>
  973. /// <returns>The number of items in the collection.</returns>
  974. /// <exception cref="ArgumentNullException"><paramref name="collection"/>
  975. /// is null.</exception>
  976. public static int Count<T>(IEnumerable<T> collection)
  977. {
  978. if (collection == null)
  979. {
  980. throw new ArgumentNullException("collection",
  981. "Unable to count number of items if no valid collection was given");
  982. }
  983. // If it's really an ICollection, use that Count property as it is much
  984. // faster.
  985. ICollection<T> genericCollection = collection as ICollection<T>;
  986. if (genericCollection != null)
  987. {
  988. return genericCollection.Count;
  989. }
  990. // Traverse the collection and count the elements.
  991. int count = 0;
  992. foreach (T item in collection)
  993. {
  994. // Dummy line to avoid Warning CA1804
  995. if (item.GetType() != null)
  996. {
  997. count++;
  998. }
  999. }
  1000. return count;
  1001. }
  1002. #endregion
  1003. #region CountEqual (Static)
  1004. /// <summary>
  1005. /// Counts the number of items in the collection that are equal to
  1006. /// <paramref name="find"/>.
  1007. /// </summary>
  1008. /// <remarks>The default sense of equality for T is used, as defined by
  1009. /// T's implementation of IComparable&lt;T&gt;.Equals or object.Equals.
  1010. /// </remarks>
  1011. /// <param name="collection">The collection to count items in.</param>
  1012. /// <param name="find">The item to compare to.</param>
  1013. /// <returns>The number of items in the collection that are equal to
  1014. /// <paramref name="find"/>.</returns>
  1015. public static int CountEqual<T>(IEnumerable<T> collection, T find)
  1016. {
  1017. return CountEqual(collection, find, EqualityComparer<T>.Default);
  1018. }
  1019. /// <summary>
  1020. /// Counts the number of items in the collection that are equal to
  1021. /// <paramref name="find"/>.
  1022. /// </summary>
  1023. /// <param name="collection">The collection to count items in.</param>
  1024. /// <param name="find">The item to compare to.</param>
  1025. /// <param name="equalityComparer">The comparer to use to determine if
  1026. /// two items are equal. Only the Equals member function will be called.
  1027. /// </param>
  1028. /// <returns>The number of items in the collection that are equal to
  1029. /// <paramref name="find"/>.</returns>
  1030. /// <exception cref="ArgumentException"><paramref name="collection"/> or
  1031. /// <paramref name="equalityComparer"/> is null.</exception>
  1032. public static int CountEqual<T>(IEnumerable<T> collection, T find,
  1033. IEqualityComparer<T> equalityComparer)
  1034. {
  1035. if (collection == null)
  1036. {
  1037. throw new ArgumentException("collection");
  1038. }
  1039. if (equalityComparer == null)
  1040. {
  1041. throw new ArgumentNullException("equalityComparer");
  1042. }
  1043. int count = 0;
  1044. foreach (T item in collection)
  1045. {
  1046. if (equalityComparer.Equals(item, find))
  1047. {
  1048. ++count;
  1049. }
  1050. }
  1051. return count;
  1052. }
  1053. #endregion
  1054. #region IsValidIndex (Static)
  1055. /// <summary>
  1056. /// Returns 'true' if the given index of the array stays in the
  1057. /// "array range".
  1058. /// </summary>
  1059. /// <param name="arrayIndex">Array index</param>
  1060. /// <param name="anyArray">Any array</param>
  1061. /// <returns>'true' if the given index of the array stays in the range
  1062. /// </returns>
  1063. public static bool IsValidIndex(this IList list, int arrayIndex)
  1064. {
  1065. return list != null &&
  1066. arrayIndex < list.Count &&
  1067. arrayIndex > MathHelper.InvalidIndex;
  1068. }
  1069. #endregion
  1070. #region Pop (Static)
  1071. /// <summary>
  1072. /// Returns the top most item of the list and removes it from the list.
  1073. /// Warning: This method is a bit slow because we need to change the list
  1074. /// and removing the last entry is not as fast as for Collections like
  1075. /// Queue, use it with care.
  1076. /// </summary>
  1077. /// <typeparam name="T">The object type in the list</typeparam>
  1078. /// <param name="list">The list we want to pop from</param>
  1079. /// <returns>The top most object of the list</returns>
  1080. public static T Pop<T>(this List<T> list)
  1081. {
  1082. if (list.Count == 0)
  1083. {
  1084. throw new Exception("The list is empty!");
  1085. }
  1086. T result = list[list.Count - 1];
  1087. list.RemoveAt(list.Count - 1);
  1088. return result;
  1089. }
  1090. #endregion
  1091. #region IsNullOrEmpty (Static)
  1092. /// <summary>
  1093. /// Helper method for a common check if an array is null or has no
  1094. /// elements. Same as String.IsNullOrEmpty
  1095. /// </summary>
  1096. /// <param name="array">The array to check.</param>
  1097. /// <returns>True if array is null or empty.</returns>
  1098. public static bool IsNullOrEmpty(Array array)
  1099. {
  1100. return array == null ||
  1101. array.Length == 0;
  1102. }
  1103. /// <summary>
  1104. /// Helper method for a common check if a list is null or has no
  1105. /// elements. Same as String.IsNullOrEmpty
  1106. /// </summary>
  1107. /// <param name="list">The list to check.</param>
  1108. /// <returns>True if list is null or empty.</returns>
  1109. public static bool IsNullOrEmpty<T>(List<T> list)
  1110. {
  1111. return list == null ||
  1112. list.Count == 0;
  1113. }
  1114. #endregion
  1115. #region SafeGet (Static)
  1116. /// <summary>
  1117. /// Gets given property value in a safe way (not found? then default is
  1118. /// returned, otherwise the found object is returned).
  1119. /// </summary>
  1120. /// <param name="dict">Dictionary</param>
  1121. /// <param name="key">Key</param>
  1122. /// <returns>Value from dictionary or default value if not found</returns>
  1123. public static ValueType SafeGet<KeyType, ValueType>(
  1124. Dictionary<KeyType, object> dict, KeyType key)
  1125. {
  1126. if (dict.ContainsKey(key) == false)
  1127. {
  1128. return default(ValueType);
  1129. }
  1130. ValueType result;
  1131. try
  1132. {
  1133. result = (ValueType)dict[key];
  1134. }
  1135. catch
  1136. {
  1137. result = default(ValueType);
  1138. }
  1139. return result;
  1140. //return (ValueType)Convert.ChangeType(dict[key], typeof(ValueType));
  1141. }
  1142. #endregion
  1143. #region Save
  1144. /// <summary>
  1145. /// Helper method to save out an array of strings by just saving the length
  1146. /// first and then all the data. Use LoadStrings to load the data again.
  1147. /// </summary>
  1148. /// <param name="someArray">Some string array with data</param>
  1149. /// <param name="writer">Binary data writer</param>
  1150. public static void Save(this string[] someArray, BinaryWriter writer)
  1151. {
  1152. if (writer == null)
  1153. {
  1154. Log.Warning("Unable to save array, writer is not valid!");
  1155. return;
  1156. }
  1157. if (someArray == null)
  1158. {
  1159. writer.Write((int)0);
  1160. return;
  1161. }
  1162. writer.Write(someArray.Length);
  1163. for (int num = 0; num < someArray.Length; num++)
  1164. {
  1165. writer.Write(someArray[num]);
  1166. }
  1167. }
  1168. /// <summary>
  1169. /// Helper method to save out an array of integers by saving the length
  1170. /// first and then all the data. Use LoadIntegers to load the data again.
  1171. /// </summary>
  1172. /// <param name="someArray">Some integer array with data</param>
  1173. /// <param name="writer">Binary data writer</param>
  1174. public static void Save(this int[] someArray, BinaryWriter writer)
  1175. {
  1176. if (writer == null)
  1177. {
  1178. Log.Warning("Unable to save array, writer is not valid!");
  1179. return;
  1180. }
  1181. if (someArray == null)
  1182. {
  1183. writer.Write((int)0);
  1184. return;
  1185. }
  1186. writer.Write(someArray.Length);
  1187. for (int num = 0; num < someArray.Length; num++)
  1188. {
  1189. writer.Write(someArray[num]);
  1190. }
  1191. }
  1192. #endregion
  1193. #region Load
  1194. /// <summary>
  1195. /// Helper method to load an array of strings by first reading the length
  1196. /// and then all the data. Use Save to save the data.
  1197. /// </summary>
  1198. /// <param name="reader">Binary data reader</param>
  1199. /// <returns>String array with all the data filled in</returns>
  1200. public static string[] LoadStrings(BinaryReader reader)
  1201. {
  1202. if (reader == null)
  1203. {
  1204. Log.Warning("Unable to read array, reader is not valid!");
  1205. return new string[0];
  1206. }
  1207. int length = reader.ReadInt32();
  1208. string[] ret = new string[length];
  1209. for (int num = 0; num < length; num++)
  1210. {
  1211. ret[num] = reader.ReadString();
  1212. }
  1213. return ret;
  1214. }
  1215. /// <summary>
  1216. /// Helper method to load an array of strings by first reading the length
  1217. /// and then all the data. Use Save to save the data.
  1218. /// </summary>
  1219. /// <param name="reader">Binary data reader</param>
  1220. /// <returns>String array with all the data filled in</returns>
  1221. public static int[] LoadIntegers(BinaryReader reader)
  1222. {
  1223. if (reader == null)
  1224. {
  1225. Log.Warning("Unable to read array, reader is not valid!");
  1226. return new int[0];
  1227. }
  1228. int length = reader.ReadInt32();
  1229. int[] ret = new int[length];
  1230. for (int num = 0; num < length; num++)
  1231. {
  1232. ret[num] = reader.ReadInt32();
  1233. }
  1234. return ret;
  1235. }
  1236. #endregion
  1237. #region FreeDataWhenMemoryIsLow (Static)
  1238. /// <summary>
  1239. /// Event handler everyone can attach to for freeing unneeded memory.
  1240. /// The primary user of this delegate are all Cache classes, which will
  1241. /// allow to free cache data when memory is low. All data will be reloaded
  1242. /// internally, so we just need some extra CPU time to recalculate
  1243. /// everything, but we can save a lot of memory without having to go to
  1244. /// real data that is currently needed, which is much harder to optimize.
  1245. /// </summary>
  1246. public static FreeMemoryDelegate FreeDataWhenMemoryIsLow;
  1247. #endregion
  1248. #region Internal
  1249. #region NumberOfCachesGenerated (Internal)
  1250. /// <summary>
  1251. /// Helper variable to keep track on how many caches were generated. Only
  1252. /// used for warnings, debugging and profiling, but cannot be inside the
  1253. /// generic Cache class because each input/output type combination would
  1254. /// have its own counter, we want to know the overall number of caches.
  1255. /// </summary>
  1256. internal static int NumberOfCachesGenerated;
  1257. #endregion
  1258. #endregion
  1259. /// <summary>
  1260. /// ArrayHelper tests
  1261. /// </summary>
  1262. internal class ArrayHelperTests
  1263. {
  1264. #region CompareArrays (Static)
  1265. /// <summary>
  1266. /// Test compare arrays. Note: Too slow for a dynamic unit test.
  1267. /// </summary>
  1268. [Test]
  1269. public static void CompareArrays()
  1270. {
  1271. // Compare 2 arrays
  1272. int[] testArray1 = new int[4]
  1273. {
  1274. 1, 4, 7, 5
  1275. };
  1276. int[] testArray2 = (int[])new int[2]
  1277. {
  1278. 1, 4
  1279. }.Add(new int[2]
  1280. {
  1281. 7, 5
  1282. });
  1283. Assert.True(Compare(testArray1, testArray2));
  1284. // Compare 2 generic lists
  1285. List<int> testList1 = new List<int>(new[]
  1286. {
  1287. 4, 8
  1288. });
  1289. List<int> testList2 = new List<int>();
  1290. testList2.Add(4);
  1291. testList2.Add(8);
  1292. Assert.True(Compare(testList1, testList2));
  1293. Assert.True(testList1.Contains(8));
  1294. Assert.False(testList1.Contains(2));
  1295. }
  1296. #endregion
  1297. #region IsNullOrEmpty (Static)
  1298. /// <summary>
  1299. /// Test the IsNullOrEmpty method.
  1300. /// </summary>
  1301. [Test]
  1302. public static void IsNullOrEmpty()
  1303. {
  1304. string[] testArray = null;
  1305. Assert.True(ArrayHelper.IsNullOrEmpty(testArray));
  1306. testArray = new string[0];
  1307. Assert.True(ArrayHelper.IsNullOrEmpty(testArray));
  1308. testArray = new[]
  1309. {
  1310. "hello"
  1311. };
  1312. Assert.False(ArrayHelper.IsNullOrEmpty(testArray));
  1313. List<string> testList = null;
  1314. Assert.True(ArrayHelper.IsNullOrEmpty(testList));
  1315. testList = new List<string>();
  1316. Assert.True(ArrayHelper.IsNullOrEmpty(testList));
  1317. testList.Add("hello");
  1318. Assert.False(ArrayHelper.IsNullOrEmpty(testList));
  1319. }
  1320. #endregion
  1321. #region SafeGet (Static)
  1322. /// <summary>
  1323. /// Test the SafeGet method.
  1324. /// </summary>
  1325. [Test]
  1326. public static void SafeGet()
  1327. {
  1328. Dictionary<string, object> elements = new Dictionary<string, object>();
  1329. Assert.Null(SafeGet<string, Array>(elements, "key1"));
  1330. elements.Add("key2", 15);
  1331. elements.Add("key3", 15.456f);
  1332. elements.Add("key4", 15.1d);
  1333. Assert.Equal(SafeGet<string, int>(elements, "key2"),
  1334. 15);
  1335. Assert.Equal(SafeGet<string, float>(elements, "key3"),
  1336. 15.456f);
  1337. Assert.Equal(SafeGet<string, double>(elements, "key4"),
  1338. 15.1d);
  1339. // Now we test an invalid cast which will return the default
  1340. Assert.Equal(SafeGet<string, int>(elements, "key4"),
  1341. 0.0d);
  1342. }
  1343. #endregion
  1344. #region Resize
  1345. /// <summary>
  1346. /// Test resize
  1347. /// </summary>
  1348. [Test]
  1349. public void Resize()
  1350. {
  1351. // Just resize a simple int array
  1352. int[] testArray1 = {
  1353. 0, 1
  1354. };
  1355. Assert.Equal(6, testArray1.Resize(6).Length);
  1356. // Resize a generic list (returning an array, much faster)
  1357. List<int> testArray3 = new List<int>(new[]
  1358. {
  1359. 0, 1
  1360. });
  1361. Assert.Equal(6, testArray3.Resize(6).Length);
  1362. }
  1363. #endregion
  1364. #region IsEqual
  1365. /// <summary>
  1366. /// Is equal
  1367. /// </summary>
  1368. [Test]
  1369. public void IsEqual()
  1370. {
  1371. int[] list = new[]
  1372. {
  1373. 1, 2, 3
  1374. };
  1375. int[] unorderedList = new[]
  1376. {
  1377. 2, 3, 1
  1378. };
  1379. int[] differentList = new[]
  1380. {
  1381. 11, 2, 3
  1382. };
  1383. Assert.True(list.IsEqualWithoutOrder(list));
  1384. Assert.True(list.IsEqualWithoutOrder(unorderedList));
  1385. Assert.False(list.IsEqualWithoutOrder(differentList));
  1386. }
  1387. #endregion
  1388. #region AddArrays
  1389. /// <summary>
  1390. /// Test add arrays
  1391. /// </summary>
  1392. [Test]
  1393. public void AddArrays()
  1394. {
  1395. // Test adding normal arrays
  1396. int[] testArray1 = {
  1397. 0, 1, 2, 3
  1398. };
  1399. int[] testArray2 = {
  1400. 4, 5, 3, 1
  1401. };
  1402. int[] testArray3 = (int[])testArray1.Add(testArray2);
  1403. Assert.Equal(testArray3.Length,
  1404. testArray1.Length + testArray2.Length);
  1405. Assert.True(Compare(testArray3,
  1406. new[]
  1407. {
  1408. 0, 1, 2, 3, 4, 5, 3, 1
  1409. }));
  1410. // Test adding generic lists
  1411. List<int> testList1 = new List<int>(new[]
  1412. {
  1413. 0, 1, 2
  1414. });
  1415. List<int> testList2 = new List<int>(new[]
  1416. {
  1417. 6, 5, 4
  1418. });
  1419. List<int> testList3 = testList1.Add(testList2);
  1420. Assert.Equal(testList3.Count,
  1421. testList1.Count + testList2.Count);
  1422. Assert.True(Compare(testList3,
  1423. new[]
  1424. {
  1425. 0, 1, 2, 6, 5, 4
  1426. }));
  1427. }
  1428. #endregion
  1429. #region RemoveIndex
  1430. /// <summary>
  1431. /// Test remove index
  1432. /// </summary>
  1433. [Test]
  1434. public void RemoveIndex()
  1435. {
  1436. int[] someArray = new[]
  1437. {
  1438. 1, 2, 6, 3, 4
  1439. };
  1440. // Remove 6 and compare
  1441. Assert.True(ArrayHelper.Compare(
  1442. ArrayHelper.RemoveIndex(someArray, 2),
  1443. new[]
  1444. {
  1445. 1, 2, 3, 4
  1446. }));
  1447. }
  1448. #endregion
  1449. #region GetSubArray
  1450. /// <summary>
  1451. /// Test get sub array
  1452. /// </summary>
  1453. [Test]
  1454. public void GetSubArray()
  1455. {
  1456. // First test
  1457. int[] someArray = new[]
  1458. {
  1459. 1, 2, 3, 100, 200, 300, 4, 5, 6
  1460. };
  1461. Assert.True(Compare(
  1462. someArray.GetSubArray(3, 3),
  1463. new[]
  1464. {
  1465. 100, 200, 300
  1466. }));
  1467. // Another test
  1468. float[] testNumbers = new float[]
  1469. {
  1470. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
  1471. };
  1472. float[] extractedNumbers = testNumbers.GetSubArray(2, 4);
  1473. Assert.Equal(new float[]
  1474. {
  1475. 2, 3, 4, 5
  1476. }, extractedNumbers);
  1477. }
  1478. #endregion
  1479. #region ConcatenateCollections
  1480. /// <summary>
  1481. /// Test concatenate collections
  1482. /// </summary>
  1483. [Test]
  1484. public void ConcatenateCollections()
  1485. {
  1486. //int[] list1 = new int[] { 0, 1, 2, 3, 4 };
  1487. //int[] list2 = new int[] { 5, 6, 7, 8, 9 };
  1488. //int[] list3 = new int[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
  1489. //int[] allLists = ArrayHelper.ToArray(ConcatenateCollections<int>(
  1490. // new int[][] { list1, list2, list3 }));
  1491. //Assert.Equal(list1.Length + list2.Length + list3.Length,
  1492. // allLists.Length);
  1493. //Assert.Equal("0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " +
  1494. // "10, 20, 30, 40, 50, 60, 70, 80, 90, 100",
  1495. // ArrayHelper.Write(allLists));
  1496. }
  1497. #endregion
  1498. #region AreCollectionsEqual
  1499. /// <summary>
  1500. /// Test are collections equal
  1501. /// </summary>
  1502. [Test]
  1503. public void AreCollectionsEqual()
  1504. {
  1505. int[] list1 = new[]
  1506. {
  1507. 1, 2, 3, 4, 5, 6
  1508. };
  1509. int[] list2 = new[]
  1510. {
  1511. 1, 2, 3, 4, 5, 6, 7
  1512. };
  1513. int[] list3 = new[]
  1514. {
  1515. 1, 2, 3, 4, 5, 6
  1516. };
  1517. Assert.False(ArrayHelper.AreCollectionsEqual(list1, list2));
  1518. Assert.True(ArrayHelper.AreCollectionsEqual(list1, list3));
  1519. }
  1520. #endregion
  1521. #region ToArray
  1522. /// <summary>
  1523. /// Test to array
  1524. /// </summary>
  1525. [Test]
  1526. public void ToArray()
  1527. {
  1528. List<string> someStrings = new List<string>();
  1529. someStrings.Add("hi");
  1530. someStrings.Add("there");
  1531. someStrings.Add("whats");
  1532. someStrings.Add("up");
  1533. string[] stringArray = ArrayHelper.ToArray(someStrings);
  1534. Assert.Equal("hi, there, whats, up",
  1535. stringArray.Write());
  1536. Assert.True(
  1537. ArrayHelper.AreCollectionsEqual(someStrings, stringArray));
  1538. }
  1539. #endregion
  1540. #region IsValidIndex
  1541. /// <summary>
  1542. /// Is valid index
  1543. /// </summary>
  1544. [Test]
  1545. public void IsValidIndex()
  1546. {
  1547. int[] testArray = new int[5];
  1548. Assert.True(testArray.IsValidIndex(0));
  1549. Assert.True(testArray.IsValidIndex(2));
  1550. Assert.True(testArray.IsValidIndex(4));
  1551. Assert.False(testArray.IsValidIndex(5));
  1552. Assert.False(testArray.IsValidIndex(-1));
  1553. }
  1554. #endregion
  1555. #region ConvertStringToIntArray
  1556. /// <summary>
  1557. /// Convert string to int array
  1558. /// </summary>
  1559. [Test]
  1560. public void ConvertStringToIntArray()
  1561. {
  1562. string testInts = "1, 2, 3, 4, 10";
  1563. int[] ints = ArrayHelper.ConvertStringToIntArray(testInts);
  1564. Assert.Equal(ints.Length, 5);
  1565. Assert.Equal(ints[0], 1);
  1566. Assert.Equal(ints[1], 2);
  1567. Assert.Equal(ints[4], 10);
  1568. // Also make sure that converting back to a string works
  1569. Assert.Equal(ints.Write(", "), testInts);
  1570. }
  1571. #endregion
  1572. }
  1573. }
  1574. }