PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/source/library/Interlace/Collections/Set.cs

https://bitbucket.org/VahidN/interlace
C# | 375 lines | 260 code | 71 blank | 44 comment | 15 complexity | 28914fd4a65a5cea19da91003f942c09 MD5 | raw file
  1. #region Using Directives and Copyright Notice
  2. // Copyright (c) 2007-2010, Computer Consultancy Pty Ltd
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. // * Neither the name of the Computer Consultancy Pty Ltd nor the
  13. // names of its contributors may be used to endorse or promote products
  14. // derived from this software without specific prior written permission.
  15. //
  16. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. // ARE DISCLAIMED. IN NO EVENT SHALL COMPUTER CONSULTANCY PTY LTD BE LIABLE
  20. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  26. // DAMAGE.
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Text;
  30. #endregion
  31. namespace Interlace.Collections
  32. {
  33. [Serializable]
  34. public class Set<T> : IEnumerable<T>
  35. {
  36. Dictionary<T, int> _members;
  37. public Set()
  38. {
  39. _members = new Dictionary<T, int>();
  40. }
  41. public Set(params T[] members)
  42. : this(members as IEnumerable<T>)
  43. { }
  44. public Set(IEnumerable<T> members)
  45. : this()
  46. {
  47. foreach(T item in members)
  48. {
  49. _members[item] = 1;
  50. }
  51. }
  52. /// <summary>
  53. /// Deprecated. Use the IEnumerable Constructor instead.
  54. /// </summary>
  55. /// <param name="members">An enumerable collection of items to put in the set.</param>
  56. /// <returns>A set initialized with the members.</returns>
  57. public static Set<T> FromEnumerable(IEnumerable<T> members)
  58. {
  59. return new Set<T>(members);
  60. }
  61. public int Count
  62. {
  63. get { return _members.Count; }
  64. }
  65. public Set<T> Copy()
  66. {
  67. return Set<T>.FromEnumerable(this);
  68. }
  69. public override bool Equals(object obj)
  70. {
  71. Set<T> rhs = obj as Set<T>;
  72. if (rhs == null) return false;
  73. if (Count != rhs.Count) return false;
  74. // If the lhs is a subset of the rhs:
  75. foreach (T item in _members.Keys)
  76. {
  77. if (!rhs._members.ContainsKey(item)) return false;
  78. }
  79. // And if the rhs is a subset of the lhs:
  80. foreach (T item in rhs._members.Keys)
  81. {
  82. if (!_members.ContainsKey(item)) return false;
  83. }
  84. // Then by definition, the sets are equal:
  85. return true;
  86. }
  87. public override int GetHashCode()
  88. {
  89. int hashCode = _members.Count;
  90. foreach (T item in _members.Keys)
  91. {
  92. hashCode ^= item.GetHashCode();
  93. }
  94. return hashCode;
  95. }
  96. public override string ToString()
  97. {
  98. if (Count == 0) return "{}";
  99. StringBuilder stringList = new StringBuilder();
  100. foreach (T item in _members.Keys)
  101. {
  102. if (stringList.Length != 0) stringList.Append(", ");
  103. stringList.Append(item.ToString());
  104. }
  105. stringList.Insert(0, "{ ");
  106. stringList.Append(" }");
  107. return stringList.ToString();
  108. }
  109. public T[] ToArray()
  110. {
  111. T[] array = new T[_members.Keys.Count];
  112. int i = 0;
  113. foreach (T item in _members.Keys)
  114. {
  115. array[i] = item;
  116. i++;
  117. }
  118. return array;
  119. }
  120. public bool Contains(T item)
  121. {
  122. return _members.ContainsKey(item);
  123. }
  124. public bool IsSubsetOf(Set<T> rhs)
  125. {
  126. foreach (T item in _members.Keys)
  127. {
  128. if (!rhs._members.ContainsKey(item)) return false;
  129. }
  130. return true;
  131. }
  132. public static Set<T> Union(Set<T> lhs, Set<T> rhs)
  133. {
  134. Set<T> newSet = new Set<T>();
  135. foreach (T item in lhs._members.Keys)
  136. {
  137. newSet._members[item] = 1;
  138. }
  139. foreach (T item in rhs._members.Keys)
  140. {
  141. newSet._members[item] = 1;
  142. }
  143. return newSet;
  144. }
  145. public static Set<T> Intersection(Set<T> lhs, Set<T> rhs)
  146. {
  147. Set<T> newSet = new Set<T>();
  148. foreach (T item in lhs._members.Keys)
  149. {
  150. if (rhs._members.ContainsKey(item))
  151. {
  152. newSet._members[item] = 1;
  153. }
  154. }
  155. return newSet;
  156. }
  157. public static Set<T> Difference(Set<T> lhs, Set<T> rhs)
  158. {
  159. Set<T> newSet = new Set<T>();
  160. foreach (T item in lhs._members.Keys)
  161. {
  162. if (!rhs._members.ContainsKey(item))
  163. {
  164. newSet._members[item] = 1;
  165. }
  166. }
  167. return newSet;
  168. }
  169. public void Clear()
  170. {
  171. _members.Clear();
  172. }
  173. public void UnionUpdate(T item)
  174. {
  175. _members[item] = 1;
  176. }
  177. public void UnionUpdate(Set<T> rhs)
  178. {
  179. foreach (T item in rhs._members.Keys)
  180. {
  181. _members[item] = 1;
  182. }
  183. }
  184. public void UnionUpdate(IEnumerable<T> rhs)
  185. {
  186. foreach (T item in rhs)
  187. {
  188. _members[item] = 1;
  189. }
  190. }
  191. public void DifferenceUpdate(T rhs)
  192. {
  193. _members.Remove(rhs);
  194. }
  195. public void DifferenceUpdate(Set<T> rhs)
  196. {
  197. foreach (T item in rhs._members.Keys)
  198. {
  199. _members.Remove(item);
  200. }
  201. }
  202. public void DifferenceUpdate(IEnumerable<T> rhs)
  203. {
  204. foreach (T item in rhs)
  205. {
  206. _members.Remove(item);
  207. }
  208. }
  209. public void IntersectionUpdate(Set<T> rhs)
  210. {
  211. List<T> itemsToRemove = new List<T>();
  212. foreach (T item in _members.Keys)
  213. {
  214. if (!rhs._members.ContainsKey(item)) itemsToRemove.Add(item);
  215. }
  216. foreach (T itemToRemove in itemsToRemove)
  217. {
  218. _members.Remove(itemToRemove);
  219. }
  220. }
  221. public static Set<T> operator +(Set<T> lhs, Set<T> rhs)
  222. {
  223. return Set<T>.Union(lhs, rhs);
  224. }
  225. public static Set<T> operator *(Set<T> lhs, Set<T> rhs)
  226. {
  227. return Set<T>.Intersection(lhs, rhs);
  228. }
  229. public static Set<T> operator -(Set<T> lhs, Set<T> rhs)
  230. {
  231. return Set<T>.Difference(lhs, rhs);
  232. }
  233. public static bool operator ==(Set<T> lhs, Set<T> rhs)
  234. {
  235. return Set<T>.Equals(lhs, rhs);
  236. }
  237. public static bool operator !=(Set<T> lhs, Set<T> rhs)
  238. {
  239. return !Set<T>.Equals(lhs, rhs);
  240. }
  241. public IEnumerator<T> GetEnumerator()
  242. {
  243. return _members.Keys.GetEnumerator();
  244. }
  245. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  246. {
  247. return _members.Keys.GetEnumerator();
  248. }
  249. public T AnyItem
  250. {
  251. get
  252. {
  253. // Grab a random item:
  254. foreach (T item in _members.Keys)
  255. {
  256. return item;
  257. }
  258. // Or if there wasn't one, throw an exception:
  259. throw new InvalidOperationException(
  260. "There must be at least one item in the set for this operation.");
  261. }
  262. }
  263. /// <summary>
  264. /// Maps the set through a function.
  265. /// </summary>
  266. /// <typeparam name="TOutput">The type of elements in the resulting set.</typeparam>
  267. /// <param name="converter">The function to map the set through.</param>
  268. /// <returns>The resulting set.</returns>
  269. /// <remarks>If the function is not one to one, the cadinality of the resulting
  270. /// set may differ from this set; this is why the function is not called "ConvertAll", despite
  271. /// being similar to the same method on lists.</remarks>
  272. public Set<TOutput> Map<TOutput>(Converter<T, TOutput> converter)
  273. {
  274. Set<TOutput> resultSet = new Set<TOutput>();
  275. foreach (T element in _members.Keys)
  276. {
  277. resultSet.UnionUpdate(converter(element));
  278. }
  279. return resultSet;
  280. }
  281. public TOutput Fold<TOutput>(Folder<T, TOutput> folder, TOutput initial)
  282. {
  283. TOutput accumulator = initial;
  284. foreach (T element in _members.Keys)
  285. {
  286. accumulator = folder(element, accumulator);
  287. }
  288. return accumulator;
  289. }
  290. public Set<T> Filter(Predicate<T> predicate)
  291. {
  292. Set<T> resultSet = new Set<T>();
  293. foreach (T element in _members.Keys)
  294. {
  295. if (predicate(element))
  296. {
  297. resultSet.UnionUpdate(element);
  298. }
  299. }
  300. return resultSet;
  301. }
  302. }
  303. public delegate TAccumulated Folder<TInput, TAccumulated>(TInput input, TAccumulated accumulated);
  304. }