예제 #1
0
        public RangeSet <T> GetExcept(RangeSet <T> rangeSet)
        {
            RangeSet <T> ret = new RangeSet <T>(this);

            ret.Remove(rangeSet);
            return(ret);
        }
예제 #2
0
        public RangeSet <T> GetUnion(RangeSet <T> rangeSet)
        {
            RangeSet <T> ret = new RangeSet <T>(this);

            ret.Add(rangeSet);
            return(ret);
        }
예제 #3
0
        /// <summary>
        /// 範囲を集合に追加します
        /// </summary>
        /// <param name="item">範囲</param>
        /// <remarks>
        /// 内部の実装的にはこのような感じ
        ///   ##### #### #### ### ###
        /// +         ########
        /// -------------------------
        ///   #####               ###
        /// +       #############
        /// -------------------------
        ///   ##### ############# ###
        /// </remarks>
        public virtual void Add(RangeSet <T> .Range item)
        {
            // 範囲の終了位置が引数の範囲の開始位置以降であるような最初の範囲を探す
            Range start = new Range(item.Start, item.Start);
            int   index = _rangeList.BinarySearch(start, _rangeEndComparer);

            if (index < 0)
            {
                index = ~index;
            }
            else
            {
                // 接触している場合
            }
            T newStart = item.Start;
            T newEnd   = item.End;

            // 引数の範囲とかぶっている部分を除く
            while (index < _rangeList.Count && _rangeList[index].Start.CompareTo(item.End) <= 0)
            {
                newStart = min(newStart, _rangeList[index].Start);
                newEnd   = max(newEnd, _rangeList[index].End);
                _rangeList.RemoveAt(index);
            }
            // 除かれた範囲と引数の範囲の和を追加
            Range newRange = new RangeSet <T> .Range(newStart, newEnd);

            if (!newRange.IsEmpty)
            {
                _rangeList.Insert(index, newRange);
            }
        }
예제 #4
0
        public bool Remove(RangeSet <T> .Range item)
        {
            // 範囲の終了位置が引数の範囲の開始位置以降であるような最初の範囲を探す
            Range start = new Range(item.Start, item.Start);
            int   index = _rangeList.BinarySearch(start, _rangeEndComparer);

            if (index < 0)
            {
                index = ~index;
            }
            else
            {
                // 接触している場合
            }
            T newStart = item.Start;
            T newEnd   = item.End;
            // 引数の範囲とかぶっている範囲を取り除く
            bool overlaps = false;

            while (index < _rangeList.Count && _rangeList[index].Start.CompareTo(item.End) <= 0)
            {
                newStart = min(newStart, _rangeList[index].Start);
                newEnd   = max(newEnd, _rangeList[index].End);
                _rangeList.RemoveAt(index);
                overlaps = true;
            }
            if (overlaps)
            {
                if (item.IsEmpty)
                {
                    // 引数の範囲が空だった場合には,消した物を元に戻す
                    _rangeList.Insert(index, new RangeSet <T> .Range(newStart, newEnd));
                }
                else
                {
                    // 引数の範囲によって部分的に覆われている範囲は,覆われなかった部分を戻す
                    if (newStart.CompareTo(item.Start) < 0)
                    {
                        _rangeList.Insert(index, new RangeSet <T> .Range(newStart, item.Start));
                        index++;
                    }
                    if (item.End.CompareTo(newEnd) < 0)
                    {
                        _rangeList.Insert(index, new RangeSet <T> .Range(item.End, newEnd));
                    }
                }
            }
            return(overlaps);
        }
예제 #5
0
        public RangeSet <T> GetIntersect(RangeSet <T> rangeSet)
        {
            RangeSet <T> ret = new RangeSet <T>();

            if (this.Count < rangeSet.Count)
            {
                foreach (var range in this)
                {
                    ret.Add(rangeSet.GetClipped(range));
                }
            }
            else
            {
                foreach (var range in rangeSet)
                {
                    ret.Add(this.GetClipped(range));
                }
            }
            return(ret);
        }
예제 #6
0
        /// <summary>
        /// 指定された範囲を含むかを返します.
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        public bool Contains(RangeSet <T> .Range item)
        {
            Range start = new Range(item.Start, item.Start);
            int   index = _rangeList.BinarySearch(start, _rangeEndComparer);

            if (index < 0)
            {
                index = ~index;
            }
            if (index >= _rangeList.Count)
            {
                return(false);
            }
            Range candidate = _rangeList[index];

            // 隣接しているのがあれば結合する
            for (index++; index < _rangeList.Count && candidate.Touches(_rangeList[index]); index++)
            {
                candidate = new RangeSet <T> .Range(candidate.Start, _rangeList[index].End);
            }
            return(candidate.Contains(item));
        }
예제 #7
0
        /// <summary>
        /// 範囲の集合のうち,指定された引数の部分を切り出します.
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        public RangeSet <T> GetClipped(Range range)
        {
            // 範囲の終了位置が引数の範囲の開始位置以降であるような最初の範囲を探す
            Range start = new Range(range.Start, range.Start);
            int   index = _rangeList.BinarySearch(start, _rangeEndComparer);

            if (index < 0)
            {
                index = ~index;
            }
            else
            {
                // 接触している場合は重複がないので無視
                index++;
            }
            // 被っている各範囲との重複部分を求める
            RangeSet <T> ret = new RangeSet <T>();

            for (; index < _rangeList.Count && _rangeList[index].Start.CompareTo(range.End) < 0; index++)
            {
                ret.Add(range.GetOverlap(_rangeList[index]));
            }
            return(ret);
        }
예제 #8
0
 public static int Total(this RangeSet <int> rangeSet)
 {
     return(rangeSet.Sum(range => range.End - range.Start));
 }