using System; using System.Collections.Generic; using System.Collections; using System.Collections.Specialized; using System.Text; using System.IO; using System.Reflection; using System.Diagnostics; using System.Threading; using System.Runtime.Serialization; namespace Sleis.Utility { /// /// Basic helper functions for dealing with collections. /// public static class CollectionUtility { public static Dictionary CreateDictionaryFromPairs(params T[] pairs) { if (MathUtility.IsOdd(pairs.Length)) { throw new ArgumentException("pairs.Length is odd"); } Dictionary dictionary = new Dictionary(); for (int i = 0; i < pairs.Length; i += 2) { dictionary.Add(pairs[i], pairs[i + 1]); } return dictionary; } public static bool IsNullOrEmpty(IEnumerable inArray) { if (inArray == null) { return true; } ICollection collection = inArray as ICollection; if (collection != null) { return (collection.Count == 0); } else { foreach (object item in inArray) { return false; } return true; } } public static bool MoreThanOne(IEnumerable inArray) { if (inArray == null) { return false; } ICollection collection = inArray as ICollection; if (collection != null) { return (collection.Count > 1); } else { int count = 0; foreach (object item in inArray) { if (++count > 1) { return true; } } return false; } } public static bool IndexInRange(IEnumerable inArray, int inIndex) { return (inIndex > -1) && (inIndex < Count(inArray)); } public static int Count(IEnumerable inArray) { if (inArray == null) { return 0; } ICollection collection = inArray as ICollection; if (collection != null) { return collection.Count; } else { int count = 0; foreach (object item in inArray) { ++count; } return count; } } public static T[] ToArray(IEnumerable inArray) { if (inArray != null) { ICollection collection = inArray as ICollection; if (collection != null) { T[] rtnArray = new T[collection.Count]; int i = 0; foreach (T item in inArray) { rtnArray[i++] = item; } return rtnArray; } else { List rtnArray = new List(); foreach (T item in inArray) { rtnArray.Add(item); } return rtnArray.ToArray(); } } else { return new T[0]; } } public static List ToList(IEnumerable inArray) { if (inArray != null) { List rtnList; ICollection collection = inArray as ICollection; if (collection != null) { rtnList = new List(collection.Count); } else { rtnList = new List(); } foreach (object item in inArray) { rtnList.Add((T)item); } return rtnList; } else { return new List(); } } public static List ToList(IEnumerable inArray) where T : K { if (inArray != null) { List rtnList; ICollection collection = inArray as ICollection; if (collection != null) { rtnList = new List(collection.Count); } else { rtnList = new List(); } foreach (K item in inArray) { rtnList.Add((T)item); } return rtnList; } else { return new List(); } } public static T[] ToArray(IEnumerable inArray) where T : K { if (inArray != null) { List rtnList; ICollection collection = inArray as ICollection; if (collection != null) { rtnList = new List(collection.Count); } else { rtnList = new List(); } foreach (K item in inArray) { rtnList.Add((T)item); } return rtnList.ToArray(); } else { return new T[0]; } } public static void InsertIntoSortedListAllowDuplicates(List inList, T inElement) { int index = inList.BinarySearch(inElement); if (index < 0) { index = ~index; } inList.Insert(index, inElement); } public static void InsertIntoSortedListAllowDuplicates(List inList, T inElement, IComparer comparer) { int index = inList.BinarySearch(inElement, comparer); if (index < 0) { index = ~index; } inList.Insert(index, inElement); } public static bool InsertIntoSortedList(List inList, T inElement) { int index = inList.BinarySearch(inElement); if (index < 0) { inList.Insert(~index, inElement); return true; } return false; } public static bool InsertIntoSortedList(List inList, T inElement, IComparer comparer) { int index = inList.BinarySearch(inElement, comparer); if (index < 0) { inList.Insert(~index, inElement); return true; } return false; } /// /// Perform a binary search on the input list attempting to locate an object represented by /// inCompareParam. Return values are the same as List.BinarySearch(). /// public static bool SortedListContains(List inList, T inValue) { return (inList.BinarySearch(inValue) >= 0); } public static bool SortedListContains(List inList, T inValue, IComparer comparer) { return (inList.BinarySearch(inValue, comparer) >= 0); } public static T FirstItem(IEnumerable inArray) { return NthItem(inArray, 0); } public static object FirstItem(IEnumerable inArray) { return NthItem(inArray, 0); } public static T NthItem(IEnumerable inArray, int index) { if (index < 0) { throw new IndexOutOfRangeException(string.Format("index \"{0}\" is negative", index.ToString())); } using (IEnumerator enumerator = inArray.GetEnumerator()) { int curIndex = 0; while (enumerator.MoveNext()) { if (curIndex++ == index) { return enumerator.Current; } } throw new IndexOutOfRangeException(string.Format("index \"{0}\" is out of range for the array length \"{1}\"", index.ToString(), curIndex.ToString())); } } public static object NthItem(IEnumerable inArray, int index) { if (index < 0) { throw new IndexOutOfRangeException(string.Format("index \"{0}\" is negative", index.ToString())); } IEnumerator enumerator = inArray.GetEnumerator(); int curIndex = 0; while (enumerator.MoveNext()) { if (curIndex++ == index) { return enumerator.Current; } } throw new IndexOutOfRangeException(string.Format("index \"{0}\" is out of range for the array length \"{1}\"", index.ToString(), curIndex.ToString())); } public static bool KeysMatch(IDictionary dictA, IDictionary dictB) { if (IsNullOrEmpty(dictA) && IsNullOrEmpty(dictB)) { return true; } if ((dictA == null) || (dictB == null) || (dictA.Count != dictB.Count)) { return false; } foreach (KeyValuePair pair in dictA) { if (!dictB.ContainsKey(pair.Key)) { return false; } } return true; } public static T[] RemoveNullElements(T[] inArray) where T : class { if (inArray == null) { return null; } bool hasNulls = false; foreach (T element in inArray) { if (element == null) { hasNulls = true; break; } } if (hasNulls) { List rtnList = new List(inArray.Length); foreach (T element in inArray) { if (element != null) { rtnList.Add(element); } } return rtnList.ToArray(); } else { return inArray; } } public static Type GetCollectionElementType(ICollection collection) { return GetCollectionElementType(collection.GetType()); } /// /// If the input type implements ICollection, return the type of elements that are stored /// in the collection; otherwise, return null. /// public static Type GetCollectionElementType(Type collectionType) { if (typeof(ICollection).IsAssignableFrom(collectionType)) { if (collectionType.IsArray) { if (collectionType.HasElementType) { return collectionType.GetElementType(); } } else if (collectionType.IsGenericType) { Type[] args = collectionType.GetGenericArguments(); if ((args.Length == 1) && typeof(ICollection<>).MakeGenericType(args).IsAssignableFrom(collectionType)) { return args[0]; } } } return null; } public static List CreateStringList(StringCollection collection) { List list = new List(); if (!CollectionUtility.IsNullOrEmpty(collection)) { list.Capacity = collection.Count; foreach (string value in collection) { list.Add(value); } } return list; } public static StringCollection CreateStringCollection(IEnumerable list) { StringCollection collection = new StringCollection(); if (list != null) { foreach (string value in list) { collection.Add(value); } } return collection; } public static void Add(T obj, ref List list) { if (list == null) { list = new List(); } list.Add(obj); } public static void Add(K key, V value, ref Dictionary dictionary) { if (dictionary == null) { dictionary = new Dictionary(); } dictionary.Add(key, value); } /// /// Create and return a collection of the type specified by collectionType, and copy any elements from elementsToCopy /// to the new array. /// public static ICollection CreateCollectionFromCollection(Type collectionType, ICollection elementsToCopy) { Type memberElementType = CollectionUtility.GetCollectionElementType(collectionType); if (memberElementType == null) { throw new ArgumentException(string.Format("The input collection type, \"{0},\" does not implement ICollection or the type of collection elements cannot be determined", collectionType.FullName)); } int collectionSize = 0; if (elementsToCopy != null) { // Value and member types are ICollections, do collection conversion here: Type elementsToCopyElementType = CollectionUtility.GetCollectionElementType(elementsToCopy); if (elementsToCopyElementType == null) { throw new ArgumentException(string.Format("The type of collection elements for elementsToCopy, \"{0},\" cannot be determined", elementsToCopy.GetType().FullName)); } if (elementsToCopyElementType != memberElementType) { throw new ArgumentException(string.Format("ICollection element types do not match: \"{0}\" vs. \"{1}\"", elementsToCopyElementType.ToString(), memberElementType.ToString())); } collectionSize = elementsToCopy.Count; } if (collectionType.IsArray) { Array newArray = Array.CreateInstance(memberElementType, collectionSize); if (collectionSize > 0) { elementsToCopy.CopyTo(newArray, 0); } return newArray; } else { if (typeof(IList).IsAssignableFrom(collectionType)) { IList newCollection = (IList)Activator.CreateInstance(collectionType, collectionSize); if (collectionSize > 0) { foreach (object element in elementsToCopy) { newCollection.Add(element); } } return newCollection; } else { throw new NotSupportedException(string.Format("The ICollection type \"{0}\" is not supported yet", collectionType.FullName)); } } } public static bool HaveSameLengths(params ICollection[] collections) { if (CollectionUtility.IsNullOrEmpty(collections)) { return true; } int length = -1; foreach (ICollection collection in collections) { if (collection == null) { if (length == -1) { length = 0; } else if (length != 0) { return false; } } else { if (length == -1) { length = collection.Count; } else if (length != collection.Count) { return false; } } } return true; } public delegate void ForEachDelegate(T obj); public delegate bool ForEachBreakDelegate(T obj); public static void ForEachBreak(IEnumerable list, ForEachBreakDelegate forEachProc) { if (!CollectionUtility.IsNullOrEmpty(list)) { foreach (T obj in list) { if (!forEachProc(obj)) { break; } } } } public static void ForEach(IEnumerable list, ForEachDelegate forEachProc) { if (!CollectionUtility.IsNullOrEmpty(list)) { foreach (T obj in list) { forEachProc(obj); } } } public static void ForEach(IEnumerable list, ForEachDelegate forEachProc) { if (!CollectionUtility.IsNullOrEmpty(list)) { foreach (object obj in list) { forEachProc(obj); } } } public static string[] PrependItemToArray(ICollection array, string itemToAdd) { return PrependItemToArray(array, itemToAdd, int.MaxValue); } public static string[] PrependItemToArray(ICollection array, string itemToAdd, int maxLength) { int newLength = (array == null) ? 1 : array.Count + 1; if (newLength > maxLength) { newLength = maxLength; } if (newLength == 0) { return new string[0]; } List rtnList = new List(newLength); rtnList.Add(itemToAdd); if ((newLength > 1) && !CollectionUtility.IsNullOrEmpty(array)) { int count = 1; foreach (string item in array) { if (!string.Equals(item, itemToAdd, StringComparison.InvariantCultureIgnoreCase)) { rtnList.Add(item); if (++count == newLength) { break; } } } } return rtnList.ToArray(); } public static StringCollection PrependItemToStringCollection(StringCollection collection, string itemToAdd) { if (collection == null) { collection = new StringCollection(); } else { for (int i = collection.Count - 1; i >= 0; --i) { string value = collection[i]; if (string.Equals(value, itemToAdd, StringComparison.InvariantCultureIgnoreCase)) { collection.RemoveAt(i); } } } collection.Insert(0, itemToAdd); return collection; } public static List CloneList(ICollection list) { if (list == null) { return null; } return new List(list); } public static List Intersect(ICollection list1, ICollection list2) { if ( CollectionUtility.IsNullOrEmpty(list1) || CollectionUtility.IsNullOrEmpty(list2) ) { return null; } if (list1 == list2) { return new List(list1); } Dictionary rtnList = new Dictionary(Math.Min(list1.Count, list2.Count)); if (list1.Count > list2.Count) { ICollection temp = list2; list2 = list1; list1 = temp; } foreach (string value in list1) { if (list2.Contains(value) && !rtnList.ContainsKey(value)) { rtnList[value] = value; } } return (rtnList.Count > 0) ? new List(rtnList.Keys) : null; } public static List CreateList(ICollection list) { List rtnList; if (CollectionUtility.IsNullOrEmpty(list)) { rtnList = new List(1); } else { rtnList = new List(list.Count + 1); rtnList.AddRange(list); } return rtnList; } public static T[] TrimArray(T[] array, int maxLength) { if ((array != null) && (array.Length > maxLength)) { Array.Resize(ref array, maxLength); } return array; } public static bool ContainsElementOfType(IEnumerable list, Type type) { if (CollectionUtility.IsNullOrEmpty(list)) { return false; } if (!typeof(T).IsAssignableFrom(type)) { return false; } foreach (T element in list) { if ((element != null) && (element.GetType() == type)) { return true; } } return false; } public static List> GetSortedByValue(Dictionary dict) where TValue : IComparable { List> list = new List>(dict); list.Sort(delegate(KeyValuePair pairA, KeyValuePair pairB) { return pairA.Value.CompareTo(pairB.Value); }); return list; } public static bool StringCollectionsAreEqual(IEnumerable c1, IEnumerable c2, StringComparison comparison) { if (Object.ReferenceEquals(c1, c2)) { return true; } if (((object)c1 == null) || ((object)c2 == null)) { return false; } IEnumerator e1 = c1.GetEnumerator(); IEnumerator e2 = c2.GetEnumerator(); for(;;) { bool moved1 = e1.MoveNext(); bool moved2 = e2.MoveNext(); if (moved1 != moved2) { return false; } if (!moved1) { return true; } if (!string.Equals(e1.Current, e2.Current, comparison)) { return false; } } } public static Dictionary CreateStringLookup(ICollection list, bool uppercaseStrings) { Dictionary lookup = null; if (!CollectionUtility.IsNullOrEmpty(list)) { lookup = new Dictionary(list.Count); foreach (string value in list) { string key = uppercaseStrings ? value.ToUpper() : value; if (!lookup.ContainsKey(key)) { lookup.Add(key, value); } } } return lookup; } } }