Mega Code Archive

 
Categories / C# / Data Types
 

Sparse Int Range

//http://isotopescreencapture.codeplex.com/ //The MIT License (MIT) using System.Collections.Generic; using System.Linq; namespace Isotope.Collections.Ranges {     public static partial class EnumerableUtil     {         public static IEnumerable<T> Single<T>(T item)         {             yield return item;         }         /// <summary>         /// Given a range (start,end) and a number of steps, will yield that a number for each step         /// </summary>         /// <param name="start"></param>         /// <param name="end"></param>         /// <param name="steps"></param>         /// <returns></returns>         public static IEnumerable<double> RangeSteps(double start, double end, int steps)         {             // for non-positive number of steps, yield no points             if (steps < 1)             {                 yield break;             }             // for exactly 1 step, yield the start value             if (steps == 1)             {                 yield return start;                 yield break;             }             // for exactly 2 stesp, yield the start value, and then the end value             if (steps == 2)             {                 yield return start;                 yield return end;                 yield break;             }             // for 3 steps or above, start yielding the segments             // notice that the start and end values are explicitly returned so that there             // is no possibility of rounding error affecting their values             int segments = steps - 1;             double total_length = end - start;             double stepsize = total_length / segments;             yield return start;             for (int i = 1; i < (steps - 1); i++)             {                 double p = start + (stepsize * i);                 yield return p;             }             yield return end;         }         public static IEnumerable<TGROUP> GroupByCount<T, TGROUP>(             IEnumerable<T> items,             int group_size,             System.Func<int, TGROUP> func_new_col,             System.Action<TGROUP, int, T> func_add) where TGROUP : class         {             if (items == null)             {                 throw new System.ArgumentNullException("items");             }             if (group_size < 1)             {                 throw new System.ArgumentOutOfRangeException("group_size");             }             if (func_new_col == null)             {                 throw new System.ArgumentNullException("func_new_col");             }             if (func_add == null)             {                 throw new System.ArgumentNullException("func_add");             }             int cur_group_size = 0;             TGROUP cur_group = null;             foreach (var item in items)             {                 if (cur_group_size == 0)                 {                     if (cur_group == null)                     {                         cur_group = func_new_col(group_size);                     }                     else                     {                         throw new System.InvalidOperationException();                     }                 }                 func_add(cur_group, cur_group_size, item);                 cur_group_size++;                 if (cur_group_size == group_size)                 {                     yield return cur_group;                     cur_group = null;                     cur_group_size = 0;                 }             }             if (cur_group_size > 0)             {                 if (cur_group == null)                 {                     throw new System.InvalidOperationException();                 }                 yield return cur_group;             }         }         public static IEnumerable<TGROUP> GroupByCount<T, TGROUP>(ICollection<T> items, ICollection<int> group_sizes, System.Func<int, TGROUP> func_new_col, System.Action<TGROUP, int, T> func_add)         {             if (items == null)             {                 throw new System.ArgumentNullException("items");             }             if (group_sizes == null)             {                 throw new System.ArgumentNullException("group_sizes");             }             if (func_new_col == null)             {                 throw new System.ArgumentNullException("func_new_col");             }             if (func_add == null)             {                 throw new System.ArgumentNullException("func_add");             }             int total_group_sizes = group_sizes.Sum();             if (total_group_sizes != items.Count)             {                 throw new System.ArgumentException("group_sizes must account for all items");             }             int items_added = 0;             for (int group_index = 0; group_index < group_sizes.Count; group_index++)             {                 int cur_group_size = group_sizes.ElementAt(group_index);                 if (cur_group_size < 0)                 {                     throw new System.ArgumentException("group_sizes contains a negative numver");                 }                 var cur_group = func_new_col(cur_group_size);                 for (int row_index = 0; row_index < cur_group_size; row_index++)                 {                     var cur_item = items.ElementAt(items_added);                     func_add(cur_group, row_index, cur_item);                     items_added++;                 }                 yield return cur_group;             }         }         public static IDictionary<K, List<V>> Bucketize<K, V>(IEnumerable<V> items, System.Func<V, K> func_get_key, IEqualityComparer<K> ieq)         {             if (items == null)             {                 throw new System.ArgumentNullException("items");             }             if (func_get_key == null)             {                 throw new System.ArgumentNullException("func_get_key");             }             var dic = new Dictionary<K, List<V>>(ieq);             foreach (var item in items)             {                 var key = func_get_key(item);                 List<V> list = null;                 bool found = dic.TryGetValue(key, out list);                 if (!found)                 {                     list = new List<V>();                     dic[key] = list;                 }                 list.Add(item);             }             return dic;         }         public static IDictionary<K, List<V>> Bucketize<K, V>(IEnumerable<V> items, System.Func<V, K> func_get_key)         {             IEqualityComparer<K> ieq = null;             return Bucketize<K, V>(items, func_get_key, ieq);         }         public static IDictionary<K, int> Histogram<K, V>(IEnumerable<V> items, System.Func<V, K> func_get_key, IEqualityComparer<K> ieq)         {             if (items == null)             {                 throw new System.ArgumentNullException("items");             }             if (func_get_key == null)             {                 throw new System.ArgumentNullException("func_get_key");             }             var dic = new Dictionary<K, int>(ieq);             foreach (var item in items)             {                 var key = func_get_key(item);                 int old_value = 0;                 bool found = dic.TryGetValue(key, out old_value);                 if (!found)                 {                     dic[key] = 1;                 }                 else                 {                     dic[key] = old_value + 1;                 }             }             return dic;         }         public static IDictionary<T, int> Histogram<T>(IEnumerable<T> items)         {             var dic = Histogram(items, i => i, null);             return dic;         }         public static List<List<T>> Chunkify<T>(IEnumerable<T> items, int chunksize)         {             var chunks = new List<List<T>>();             List<T> cur_chunk = null;             Chunkify(items, chunksize,                 () =>                 {                     cur_chunk = new List<T>(chunksize); chunks.Add(cur_chunk);                 },                 item =>                 {                     cur_chunk.Add(item);                 });             return chunks;         }         public static void Chunkify<T>(IEnumerable<T> items, int chunksize, System.Action create_chunk, System.Action<T> add_item)         {             if (items == null)             {                 throw new System.ArgumentNullException("items");             }             if (chunksize < 1)             {                 throw new System.ArgumentOutOfRangeException("chunksize");             }             int item_count = 0;             int curchunk_size = 0;             foreach (T item in items)             {                 if ((item_count % chunksize) == 0)                 {                     create_chunk();                     curchunk_size = 0;                 }                 add_item(item);                 item_count++;                 curchunk_size++;             }         }     }     public struct IntRange     {         public readonly int _Lower;         public readonly int _Length;         public int Lower         {             get { return this._Lower; }         }         public int Upper         {             get { return this.Lower + this.Length - 1; }         }         public int Length         {             get { return this._Length;  }         }                      private IntRange(int lower, int length)         {             this._Lower = lower;             this._Length = length;             if (this.Lower > this.Upper)             {                 throw new System.OverflowException();             }         }         /// <summary>         /// Creates a range from the lower and upper values         /// </summary>         /// <example>         /// (0,0) -> [0]         /// (0,1) -> [0,1]         /// (0,5) -> [0,1,2,3,4,5]         /// (2,5) -> [2,3,4,5]         /// </example>         /// <param name="lower"></param>         /// <param name="upper"></param>         /// <returns></returns>         public static IntRange FromEndpoints(int lower, int upper)         {             return new IntRange(lower, upper - lower + 1);         }         /// <summary>         /// Creates a range of a single number         ///  </summary>         /// <example>         /// </example><param name="value"></param>         /// <returns></returns>         public static IntRange FromInteger(int value)         {             return new IntRange(value, 1);         }                      /// <summary>         /// Creates a new range from a starting value and including all the numbers following that         ///  </summary>         /// <example>         /// (2,0) -> []         /// (2,1) -> [2]         /// (2,2) -> [2,3]         /// (2,3) -> [2,3,4]         /// (2,4) -> [2,3,4,5]         /// </example>         /// <param name="lower"></param>         /// <param name="length"></param>         /// <returns></returns>         public static IntRange FromLower(int lower, int length)         {             if (length < 0)             {                 throw new System.ArgumentOutOfRangeException("length", "must be >= 0");             }             return new IntRange(lower, length);         }         public override string ToString()         {             var invariant_culture = System.Globalization.CultureInfo.InvariantCulture;             return string.Format(invariant_culture, "Range({0},{1})", this.Lower, this.Upper);         }         private static bool _intersects(IntRange range1, IntRange range2)         {             return ((range1.Lower <= range2.Lower) && (range1.Upper >= range2.Lower));         }                      /// <summary>         /// Tests if this range interests with another         /// </summary>         /// <param name="range">the other range</param>         /// <returns>true if they intersect</returns>         public bool Intersects(IntRange range)         {             return (_intersects(this, range) || _intersects(range, this));         }                      private static int Delta = 1;         private static bool _touches(IntRange range1, IntRange range2)         {             var val = (range1.Upper + Delta) == range2.Lower;             return val;         }                      /// <summary>         /// Tests if this range touches another. For example (1-2) touches (3,5) but (1,2) does not touch (4,5)         /// </summary>         /// <param name="range">the other range</param>         /// <returns>true if they touch</returns>         public bool Touches(IntRange range)         {             var val = _touches(this, range) || _touches(range, this);             return val;         }                      /// <summary>         /// Tests if this range contains a specific integer         /// </summary>         /// <param name="n">the integet</param>         /// <returns>true if the number is contained</returns>         public bool Contains(int n)         {             return ((this.Lower <= n) && (n <= this.Upper));         }                      /// <summary>         /// Join this range with another and return a single range that contains them both. The ranges must either touch or interest.         /// for example (0,2) amd (3,7) will yield (0,7)         /// </summary>         /// <param name="range">the other range</param>         /// <returns>the merged range</returns>         public IntRange JoinWith(IntRange range)         {             if (this.Intersects(range) || this.Touches(range))             {                 int new_Upper = System.Math.Max(this.Upper, range.Upper);                 int new_Lower = System.Math.Min(this.Lower, range.Lower);                 return IntRange.FromEndpoints(new_Lower, new_Upper);             }             else             {                 throw new System.ArgumentException();             }         }         /// <summary>         /// Get each int int he range from the lower value to the upper value         /// </summary>         /// <returns>each int in the range</returns>         public IEnumerable<int> Values         {             get             {                 for (int i = this.Lower; i <= this.Upper; i++)                 {                     yield return i;                 }             }         }     }     public class SparseIntRange     {         private List<IntRange> ranges;         public SparseIntRange()         {             this.clear();         }         public IEnumerable<IntRange> Ranges         {             get             {                 foreach (var range in this.ranges)                 {                     yield return range;                 }             }         }         public IEnumerable<int> Values         {             get             {                 foreach (var rng in this.Ranges)                 {                     foreach (int i in rng.Values)                     {                         yield return i;                     }                 }             }         }         private void clear()         {             this.ranges = new List<IntRange>();         }         public int RangeCount         {             get { return this.ranges.Count; }         }         public void Add(int n)         {             var rng = IntRange.FromInteger(n);             this.Add(rng);         }         public void AddInclusive(int lower, int upper)         {             var rng = IntRange.FromEndpoints(lower, upper);             this.Add(rng);         }         public void Add(IntRange range)         {             var left = new List<IntRange>();             var right = new List<IntRange>();             foreach (var rng in this.ranges)             {                 if (range.Intersects(rng) || range.Touches(rng))                 {                     range = range.JoinWith(rng);                 }                 else if (rng.Upper < range.Lower)                 {                     left.Add(rng);                 }                 else if (range.Upper < rng.Lower)                 {                     right.Add(rng);                 }                 else                 {                     throw new System.InvalidOperationException("Internal Error");                 }             }             this.ranges = left.Concat(EnumerableUtil.Single(range)).Concat(right).ToList();         }         public int Lower         {             get             {                 if (this.ranges.Count < 1)                 {                     throw new System.InvalidOperationException("There are no ranges");                 }                 return this.ranges[0].Lower;             }         }         public int Upper         {             get             {                 if (this.ranges.Count < 1)                 {                     throw new System.InvalidOperationException("empty");                 }                 return this.ranges[this.ranges.Count - 1].Upper;             }         }         public int Count         {             get             {                 int length = this.ranges.Aggregate(0, (old, rng) => old + rng.Length);                 return length;             }         }         public void Remove(int value)         {             var rng = IntRange.FromInteger(value);             this.Remove(rng);         }         public void RemoveInclusive(int lower, int upper)         {             var rng = IntRange.FromEndpoints(lower, upper);             this.Remove(rng);         }         public void Remove(IntRange range)         {             // if the range doesn't intersect this collection do nothing             if (!range.Intersects(IntRange.FromEndpoints(this.Lower, this.Upper)))             {                 return;             }             var middle = new List<IntRange>();             foreach (var S in this.ranges)             {                 if (!range.Intersects(S))                 {                     middle.Add(S);                     continue;                 }                 if ((range.Lower <= S.Lower) && (range.Upper >= S.Upper))                 {                     // disregard S completely                     continue;                 }                 if (range.Lower > S.Lower)                 {                     if (S.Lower <= (range.Lower - 1))                     {                         var X = IntRange.FromEndpoints(S.Lower, range.Lower - 1);                         middle.Add(X);                     }                 }                 if (range.Upper <= S.Upper)                 {                     if ((range.Upper + 1) <= S.Upper)                     {                         var X = IntRange.FromEndpoints(range.Upper + 1, S.Upper);                         middle.Add(X);                     }                 }                 else                 {                     throw new System.InvalidOperationException("internal error");                 }             }             this.ranges = middle;         }         public IntRange? FindRangeContainingNumber(int n)         {             foreach (var rng in this.ranges)             {                 if (rng.Contains(n))                 {                     return rng;                 }             }             return null;         }         public bool Contains(int n)         {             var rng = this.FindRangeContainingNumber(n);             return rng != null ? true : false;         }         public override string ToString()         {             var sb = new System.Text.StringBuilder();             sb.AppendFormat("{0}(", this.GetType().Name);             foreach (var rng in this.ranges)             {                 sb.Append(rng.ToString());             }             sb.Append(")");             return sb.ToString();         }     } }