Sparse Int Range : Number « Data Types « C# / C Sharp






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();
        }
    }
}

   
    
    
  








Related examples in the same category

1.Converting Degrees to RadiansConverting Degrees to Radians
2.Converting Radians to DegreesConverting Radians to Degrees
3.Converting a Number in Another Base to Base10Converting a Number in Another Base to Base10
4.Determining if a String is a Valid Number by Parse functionsDetermining if a String is a Valid Number by Parse functions
5.Use regualr expression to check: is it a numberUse regualr expression to check: is it a number
6.Use int.Parse to check: is it an integerUse int.Parse to check: is it an integer
7.Use Integer.Parse to check: is it a numberUse Integer.Parse to check: is it a number
8.Use regualr expression to check: Is it an Unsigned IntegerUse regualr expression to check: Is it an Unsigned Integer
9.Use regular expression to get number from stringUse regular expression to get number from string
10.Faster way to get number from stringFaster way to get number from string
11.Converting Celsius to FahrenheitConverting Celsius to Fahrenheit
12.Converting Fahrenheit to CelsiusConverting Fahrenheit to Celsius
13.Is it a double numberIs it a double number
14.Test for an Even or Odd ValueTest for an Even or Odd Value
15.System maximums and minimumsSystem maximums and minimums
16.Declare int and use itDeclare int and use it
17.Use int variableUse int variable
18.shows that using an instance of the System.Int32 stucture is the same as using the int keywordshows that using an instance of the System.Int32 stucture is the same as using the int keyword
19.Numeric Parsing DemoNumeric Parsing Demo
20.Number calculation utils
21.Double Range
22.Int Range
23.Sparse Double Range
24.Checks if a value is in a range (inclusive)
25.Determines whether the specified value is null.
26.Converts specified value to nullable value.
27.Validate number
28.Native SizeOf
29.Is Numeric