Add or subtract many ranges, such as "1,2,4,10-25,40 +" + "3,11,26",

I am writing a C # program where the user can enter a range of values ​​in sets, for example, "1,2,4,10-25,40 +", where elements can be an individual number, a range of 10-25, and a range to infinity, for example, 25+. Ranges must be at least 2 from each other, you cannot say 10-11, which should be 10.11. I need functions to add and subtract.

For example, "1,2,4,10-25,40 +" + "3,11,26" will return "1-4,10-26,40 +"

I use the strings as an example here, but I assume that the data can already be parsed into objects for three categories: a single number, a range, an infinite range. I am not asking how to parse strings.

I am writing my own set of functions and I see that there is a lot of complexity due to the fact that the ranges must be divided into two parts. I know that there are functions to check if a number is in the same range, and it easily integrates into the routine to check if the number is in the range set.

But how can I add or subtract sets and simplify them so that instead you get 11,12,13, but 11-13? This is not trivial. I am open to any solution and can import libraries if necessary.

+4
source share
3 answers

Here is a little function I wrote to help you ... fiddle

Excerpt

private static List<string> Simplify(List<string> inputs)
{
    var simpleList = new List<int>();
    var retval = new List<string>();
    bool infinity = false;

    foreach (string input in inputs)
    {
        if (string.IsNullOrEmpty(input))
            continue;

        if (input.Split('-').Length > 1)
        {
            int min = int.Parse(input.Split('-')[0].Trim());
            int max = int.Parse(input.Split('-')[1].Trim());

            // inclusive
            simpleList.AddRange(Enumerable.Range(min, max - min + 1));

            continue;
        }

        if (input.Trim().EndsWith("+"))
        {
            infinity = true;
            simpleList.Add(int.Parse(input.Trim().Trim('+')));
        } else simpleList.Add(int.Parse(input.Trim()));
    }

    simpleList.Sort();

    for (int i = 0; i < simpleList.Count; i++)
    {
        int currentVal = simpleList[i];
        int q = i;
        while (q < simpleList.Count)
        {
            if (q != simpleList.Count - 1 && simpleList[q] + 1 == simpleList[q + 1])
            {
                q++;
                continue;
            }
            if (currentVal == simpleList[q])
            {
                retval.Add(currentVal.ToString());
                i = q;
                break;
            }
            if (currentVal + 1 == simpleList[q])
            {
                retval.Add(currentVal.ToString());
                retval.Add(simpleList[q].ToString());
                i = q;
                break;
            }
            retval.Add(currentVal + "-" + simpleList[q]);
            i = q;
            break;
        }
    }

    if (infinity)
        retval[retval.Count - 1] = retval[retval.Count - 1] + "+";

    return retval;
}

Test case:

var inputs = new List<string> {"11", "12", "13", "14-18", "2-3", "25", "82+", "9"};

var simplifiedList = Simplify(inputs);

foreach (string input in simplifiedList)
{
    Console.WriteLine(input);
}

Conclusion:

2
3
9
11-18
25
82+
0
source

, . ints ( BTW), num (num), ( ) (num -1). - | . , , . , , .cs , . jsut VS.

, : ( .)

List > result = AddSequences (StringToSequence ( "10,11,12-14,20-30,40 +" ), StringToSequence ( "15,16,21-41,50 +" ));

List > result = SubtractSequences (StringToSequence ( "10,11,20-30,40 +" ), StringToSequence ( "21-41,50 +" ));

List > result = StringToSequence ( "1-5,8,10,11-29,30 +, 19-25,30-40, 50+, 60 +" );

    //-------------------sequence tools-----------------------------
    public static string SequenceToString(List<List<int>> seq) {
    string ret = "";
    foreach (List<int> pair in seq) {
        if (pair.Count == 1)
        ret = ret + pair[0].ToString() + ",";
        else {
        if (pair[1] != -1)
            ret = ret + pair[0].ToString() + "|" + pair[1].ToString() + ",";
        else
            ret = ret + pair[0].ToString() + "+,";
        }
    }
    return ret;
    }

public static List<List<int>> StringToSequence(string seq) {
    List<List<int>> ret = new List<List<int>>();
    //make sure we have a list of integers
    //turn into a List<List<int>>
    //use -1 as second item to indicate the +
    List<List<int>> pairs = new List<List<int>>();
    //int usesPlus = -1;
    //split by commas
    string[] items = seq.RemoveCharsExcept("|.,-+").Split(',');
    foreach (string str in items) {
    //see if we have a dash
    if (str.Contains("-") || str.Contains("|")) {
        string[] tmp1;
        if (str.Contains("-"))
        tmp1 = str.Split('-');
        else 
        tmp1 = str.Split('|');
        //the RemoveChars() is to get rid of a + if there
        if (tmp1.Count() == 2 && tmp1[0].RemoveChars().IsInteger() && tmp1[1].RemoveChars().IsInteger()) {
        int int1 = tmp1[0].RemoveChars().ToInteger();
        int int2 = tmp1[1].RemoveChars().ToInteger();
        if (int2 > int1)
            if (int2 - int1 == 1) {
            pairs.Add(new List<int>() { int1 });
            pairs.Add(new List<int>() { int2 });
            }
            else
            pairs.Add(new List<int>() { int1, int2 });
        }
    }
    else if (str.RemoveChars().IsInteger()) {
        int tmp = str.RemoveChars().ToInteger();
        if (str.Right(1) == "+")
        pairs.Add(new List<int>() { str.RemoveChars().ToInteger(), -1 });
        else
        pairs.Add(new List<int>() { str.RemoveChars().ToInteger() });
    }
    }
    //now sort list by first item
    ret = pairs.OrderBy(o => o[0]).ToList();
    DelSequenceDupes(ret);
    CombineSequenceNums(ret);
    CombineSequenceMergeNumsToSeqs(ret);
    CombineSequenceSeqs(ret);
    TrimSequenceByPlusNums(ret);
    return ret;
}

//all these assume items are in order by first element
public static List<List<int>> AddSequences(List<List<int>> origSeq, List<List<int>> addSeq) {
    List<List<int>> ret = new List<List<int>>();
    //add in items and clean up
    origSeq.AddRange(addSeq);
    //sort list by first item
    ret = origSeq.OrderBy(o => o[0]).ToList();
    DelSequenceDupes(ret);
    CombineSequenceNums(ret);
    CombineSequenceMergeNumsToSeqs(ret);
    CombineSequenceSeqs(ret);
    TrimSequenceByPlusNums(ret);
    return ret;
}

public static List<List<int>> DelSequenceDupes(List<List<int>> seq) {
    List<List<int>> ret = new List<List<int>>();
    List<int> prev = new List<int>();
    foreach (List<int> pair in seq) {
    if (prev.Count == 0) {
        ret.Add(pair);
        prev = pair;
    }
    else if (prev.Count != pair.Count || prev[0] != pair[0] || prev[1] != pair[1]) {
        ret.Add(pair);
        prev = pair;
    }
    }
    return ret;
}

public static List<List<int>> CombineSequenceNums(List<List<int>> seq) {
    List<List<int>> ret = new List<List<int>>();
    int conscount = 0;
    int previtem = -1;
    foreach (List<int> pair in seq) {
    if (pair.Count == 1) {
        if (conscount == 0) {
        previtem = pair[0];
        conscount++;
        }
        else {
        if (pair[0] == previtem + 1) {
            previtem = pair[0];
            conscount++;
        }
        //else deal with any sequences or not, and start over
        else {
            if (conscount < 3) {
            for (int i = conscount - 1; i >= 0; i--) {
                ret.Add(new List<int>() { previtem - i });
            }
            }
            //else its a sequence
            else {
            ret.Add(new List<int>() { previtem - (conscount - 1), previtem });
            }
            //start over on this number
            previtem = pair[0];
            conscount = 1;
        }
        }
    }
    else {
        //if on a sequence, see if conscount is more than 2
        if (conscount < 3) {
        for (int i = conscount - 1; i >= 0; i--) {
            ret.Add(new List<int>() { previtem - i });
        }
        }
        //else its a sequence
        else {
        ret.Add(new List<int>() { previtem - (conscount - 1), previtem });
        }
        //start over on bogus previtem
        previtem = -1;
        conscount = 0;
        //now add the sequence as is
        ret.Add(pair);
    }
    }
    //add any hanging numbers
    //if on a sequence, see if conscount is more than 2
    if (conscount < 3) {
    for (int i = conscount - 1; i >= 0; i--) {
        ret.Add(new List<int>() { previtem - i });
    }
    }
    //else its a sequence
    else {
    ret.Add(new List<int>() { previtem - (conscount - 1), previtem });
    }
    return ret;
}

public static List<List<int>> CombineSequenceSeqs(List<List<int>> seq) {
    List<List<int>> ret = new List<List<int>>();
    List<int> prevseq = new List<int>();
    foreach (List<int> pair in seq) {
    if (pair.Count == 1) {
        //add previous sequence if any
        if (prevseq.Count > 0) {
        ret.Add(prevseq);
        prevseq = new List<int>();
        }
        ret.Add(pair);
    }
    //else if a sequence
    else {
        if (pair[1] == -1) {
        //add previous sequence if any
        if (prevseq.Count > 0) {
            ret.Add(prevseq);
            prevseq = new List<int>();
        }
        ret.Add(pair);
        }
        else {
        if (prevseq.Count == 0) {
            prevseq = pair;
        }
        //if adjacent or any overlap, combine
        else {
            if (prevseq[1] + 1 >= pair[0]) {
            prevseq = new List<int>() { prevseq[0], Math.Max(pair[1], prevseq[1]) };
            }
            else {
            ret.Add(prevseq);
            prevseq = pair;
            }
        }
        }
    }
    }
    //add at end
    if (prevseq.Count > 0)
    ret.Add(prevseq);
    return ret;
}

public static List<List<int>> CombineSequenceMergeNumsToSeqs(List<List<int>> seq) {
    List<List<int>> ret = new List<List<int>>();
    int index = 0;
    while (index < seq.Count) {
    List<int> pair = seq[index];
    //if a number, add to ret
    if (pair.Count == 1 || (pair.Count == 2 && pair[1] == -1)) {
        ret.Add(pair);
        index++;
    }
    else {
        //if on a seq, look behind and ahead for numbers to gobble
        int lookback = 1;
        List<int> newpair = pair;
        bool go = true;
        while (go &&
           index > 0 &&
           index - lookback > -1) {
        if (seq[index - lookback].Count == 1 &&
            seq[index - lookback][0] == newpair[0] - 1) {
            //remove last item from ret
            ret.RemoveAt(ret.Count - 1);
            //modify newpair
            newpair[0] = newpair[0] - 1;
            lookback++;
        }
        else
            go = false;
        }
        //now look ahead, careful to get rid of item in the range already
        int lookahd = 1;
        go = true;
        while (go &&
           index < seq.Count + 1 &&
           index + lookahd < seq.Count) {
        if (seq[index + lookahd].Count == 1) {
            //if in range already
            if (seq[index + lookahd][0] <= newpair[1])
            lookahd++;
            else if (seq[index + lookahd][0] == newpair[1] + 1) {
            //modify newpair
            newpair[1] = newpair[1] + 1;
            lookahd++;
            }
            else
            go = false;
        }
        else
            go = false;
        }
        //add newpair to ret
        ret.Add(newpair);
        //jump past items done
        index = index + lookahd;
    }
    }
    return ret;
}

public static List<List<int>> TrimSequenceByPlusNums(List<List<int>> seq) {
    List<List<int>> ret = new List<List<int>>();
    //get sequence info
    int lowPlsNum;
    int highest = FindHighestInSeq(seq, out lowPlsNum);
    if (lowPlsNum != -1) {
    foreach (List<int> pair in seq) {
        if (pair.Count == 1) {
        if (pair[0] < lowPlsNum)
            ret.Add(pair);
        }
        else {
        if (pair[1] == -1) {
            if (pair[0] == lowPlsNum)
            ret.Add(pair);
        }
        else {
            if (pair[1] < lowPlsNum) {
            ret.Add(pair);
            }
            else if (pair[0] < lowPlsNum && pair[1] >= lowPlsNum)
            ret.Add(new List<int>() { pair[0], lowPlsNum - 1 });
        }
        }
    }
    }
    else
    ret = seq;
    return ret;
}

//assumes subtSeq has been cleaned so items are in order
public static List<List<int>> SubtractSequences(List<List<int>> origSeq, List<List<int>> subtSeq) {
    List<List<int>> ret = new List<List<int>>();
    if (subtSeq.Count > 0) {
    //go through origSeq and modify any items
    foreach (List<int> pair in origSeq) {
        //case 1 - just one number
        if (pair.Count == 1) {
        if (!IsPtInSequence(subtSeq, pair[0]))
            //add if not in subt sequence
            ret.Add(pair);
        }
        //case 2 - a sequence in orig
        else if (pair.Count == 2 && pair[1] != -1) {
        //must chop up based on items in subt
        List<List<int>> res = SubtractFromNonPlusSequence(pair, subtSeq);
        if (res.Count > 0)
            ret.AddRange(res);
        }
        //a number+
        else if (pair.Count == 2 && pair[1] == -1) {
        List<List<int>> res = SubtractFromPlusSequence(pair, subtSeq);
        if (res.Count > 0)
            ret.AddRange(res);
        }
    }
    }
    return ret;
}
//subtract a num+ by sequence
//origSeq  must have a -1 as second item
public static List<List<int>> SubtractFromPlusSequence(List<int> origSeq, List<List<int>> subtSeq) {
    List<List<int>> ret = new List<List<int>>();
    //handle by converting the num+ to a sequence plus a num+ if needed
    //find largest number in subtSeq
    int lowPlsNum;
    int largest = FindHighestInSeq(subtSeq, out lowPlsNum);
    List<int> tmpseq;
    //now make temp sequence
    if (lowPlsNum == -1) {
    //return original as its all before
    if (largest < origSeq[0]) {
        ret = new List<List<int>>() { origSeq };
    }
    else {
        //if overlap of 1
        if (largest - origSeq[0] == 1) {
        if (!IsPtInSequence(subtSeq, origSeq[0]))
            ret.Add(new List<int>() { origSeq[0] });
        }
        else if (largest - origSeq[0] == 2) {
        if (!IsPtInSequence(subtSeq, origSeq[0]))
            ret.Add(new List<int>() { origSeq[0] });
        if (!IsPtInSequence(subtSeq, origSeq[0] + 1))
            ret.Add(new List<int>() { origSeq[0] + 1 });
        }
        else {
        tmpseq = new List<int>() { origSeq[0], largest - 1 };
        ret.AddRange(SubtractFromNonPlusSequence(tmpseq, subtSeq));
        }
        //add a plus after all, since subtSeq did not have a +num in it
        ret.Add(new List<int>() { largest + 1, -1 });
    }
    }
    else {
    //its got a plus in it, just do before the subtract +
    if (lowPlsNum - origSeq[0] == 1) {
        ret.Add(new List<int>() { origSeq[0] });
    }
    else if (lowPlsNum - origSeq[0] == 2) {
        ret.Add(new List<int>() { origSeq[0] });
        ret.Add(new List<int>() { origSeq[0] + 1 });
    }
    else {
        tmpseq = new List<int>() { origSeq[0], lowPlsNum - 1 };
        ret.AddRange(SubtractFromNonPlusSequence(tmpseq, subtSeq));
    }
    //else return blank as it got wiped out
    }
    return ret;
}

//subtract a sequence (2 items) using another
public static List<List<int>> SubtractFromNonPlusSequence(List<int> origSeq, List<List<int>> subtSeq) {
    List<List<int>> ret = new List<List<int>>();
    //as we go along, curseq will be the term at hand to possibly chop
    List<int> curseq = origSeq;
    bool done = false;
    foreach (List<int> chopr in subtSeq) {
    if (!done) {
        //if chopping with one number
        if (chopr.Count == 1) {
        #region Chop with one
        //test if chop at all
        if (chopr[0] < curseq[0] || chopr[0] > curseq[1]) {
            ret.Add(curseq);
            done = true;
        }
        else {
            //handle left side of chop
            if (chopr[0] - curseq[0] == 1) {
            ret.Add(new List<int>() { curseq[0] });
            }
            else if (chopr[0] - curseq[0] == 2) {
            ret.Add(new List<int>() { curseq[0] });
            ret.Add(new List<int>() { curseq[0] + 1 });
            }
            else if (chopr[0] - curseq[0] > 2) {
            ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
            }
            //handle right side of chop
            if (curseq[1] - chopr[0] == 1) {
            ret.Add(new List<int>() { curseq[1] });
            done = true;
            }
            else if (curseq[1] - chopr[0] == 2) {
            ret.Add(new List<int>() { curseq[1] - 1 });
            ret.Add(new List<int>() { curseq[1] });
            done = true;
            }
            else if (curseq[1] - chopr[0] > 2) {
            curseq = new List<int>() { chopr[0] + 1, curseq[1] };
            }
        }
        }
        #endregion
        //now look at a chopper sequence
        else {
        //if a number +
        if (chopr[1] == -1) {
            #region Chop with one+
            //only 3 cases matter
            //if at or before start
            if (chopr[0] <= curseq[0]) {
            //stop
            done = true;
            }
            else if (chopr[0] > curseq[1]) {
            //do nothing
            }
            //if past start by 1
            else if (chopr[0] == curseq[0] + 1) {
            ret.Add(new List<int>() { curseq[0] });
            done = true;
            }
            //if past start by 2
            else if (chopr[0] == curseq[0] + 2) {
            ret.Add(new List<int>() { curseq[0] });
            ret.Add(new List<int>() { curseq[0] + 1 });
            //stop here because discard the rest
            done = true;
            }
            //if past start by more than 2
            else {
            ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
            done = true;
            }
        }
            #endregion
        //if a sequence
        else {
            #region Chop with seq
            //complete overlap
            if (curseq[0] >= chopr[0] && curseq[1] <= chopr[1]) {
            done = true;
            }
            //if we overlap chop start
            else if (chopr[1] == curseq[0]) {
            curseq = new List<int>() { curseq[0] + 1, curseq[1] };
            }
            //if we overlap chop end
            else if (chopr[0] == curseq[1]) {
            curseq = new List<int>() { curseq[0], curseq[1] - 1 };
            }
            //if we enclose chopper
            else if (chopr[0] > curseq[0] && chopr[1] < curseq[1]) {
            //handle left side
            if (chopr[0] - curseq[0] == 1) {
                ret.Add(new List<int>() { curseq[0] });
            }
            else if (chopr[0] - curseq[0] == 2) {
                ret.Add(new List<int>() { curseq[0] });
                ret.Add(new List<int>() { curseq[0] + 1 });
            }
            else {
                ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
            }
            //handle right side
            if (curseq[1] - chopr[1] == 1) {
                ret.Add(new List<int>() { curseq[1] });
                done = true;
            }
            else if (curseq[1] - chopr[1] == 2) {
                ret.Add(new List<int>() { curseq[1] - 1 });
                ret.Add(new List<int>() { curseq[1] });
                done = true;
            }
            else {
                curseq = new List<int>() { chopr[1] + 1, curseq[1] };
            }
            }
            //if we overlap past chop start
            else if (chopr[0] < curseq[0] && chopr[1] > curseq[0] && chopr[1] < curseq[1]) {
            //see if we leave nums or a sequence
            if (curseq[1] - chopr[1] == 1) {
                ret.Add(new List<int>() { curseq[1] });
                done = true;
            }
            else if (curseq[1] - chopr[1] == 2) {
                ret.Add(new List<int>() { curseq[1] - 1 });
                ret.Add(new List<int>() { curseq[1] });
                done = true;
            }
            else {
                curseq = new List<int>() { chopr[1] + 1, curseq[1] };
            }
            }
            //if we overlap before chop end
            else if (chopr[0] > curseq[0] && chopr[0] < curseq[1] && chopr[1] >= curseq[1]) {
            //see if we leave nums or a sequence
            if (chopr[0] - curseq[0] == 1) {
                ret.Add(new List<int>() { curseq[0] });
                done = true;
            }
            else if (chopr[0] - curseq[0] == 2) {
                ret.Add(new List<int>() { curseq[0] });
                ret.Add(new List<int>() { curseq[0] + 1 });
                done = true;
            }
            else {
                ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
                done = true;
            }
            }
        }
            #endregion
        }
    }
    }
    if (!done)
    ret.Add(curseq);
    return ret;
}

//find highest number in sequence, as well as lowest +num if an
//lowPlsNum is -1 if not found
public static int FindHighestInSeq(List<List<int>> seq, out int lowPlsNum) {
    //find largest number in subtSeq
    int ret = 0;
    //track lowest num+ if found in subtSeq
    lowPlsNum = -1;
    foreach (List<int> pair in seq) {
    if (pair.Count == 1) {
        if (pair[0] > ret)
        ret = pair[0];
    }
    else if (pair.Count == 2 && pair[1] != -1) {
        if (pair[1] > ret)
        ret = pair[1];
    }
    else if (pair.Count == 2 && pair[1] == -1) {
        if (lowPlsNum == -1)
        lowPlsNum = pair[0];
        if (pair[0] < lowPlsNum)
        lowPlsNum = pair[0];
    }
    }
    return ret;
}

public static bool IsPtInSequence(List<List<int>> seq, int ptnum) {
    bool ret = false;
    foreach (List<int> lst in seq) {
    if (lst.Count == 1) {
        if (lst[0] == ptnum)
        ret = true;
    }
    else if (lst.Count == 2) {
        //check if plus item
        if (lst[1] == -1) {
        if (ptnum >= lst[0])
            ret = true;
        }
        else if (ptnum >= lst[0] && ptnum <= lst[1])
        ret = true;
    }
    }
    return ret;
}

public static string RemoveChars(this string s) {
    string str = "";
    foreach (char c in s) {
        if (char.IsDigit(c) || c == '.' || c == ',' || c == '-') {
            str = str + c.ToString();
        }
    }
    return str;
}

//keep is list of single chars
public static string RemoveCharsExcept(this string s, string keep) {
    string str = "";
    foreach (char c in s) {
    if (char.IsDigit(c) || keep.Contains(c)) {
        str = str + c.ToString();
    }
    }
    return str;
}

/// <summary>
/// Returns the last few characters of the string with a length
/// specified by the given parameter. If the string length is less than the 
/// given length the complete string is returned. If length is zero or 
/// less an empty string is returned
/// </summary>
/// <param name="s">the string to process</param>
/// <param name="length">Number of characters to return</param>
/// <returns></returns>
public static string Right(this string s, int length) {
    length = Math.Max(length, 0);
    if (s.Length > length) {
        return s.Substring(s.Length - length, length);
    }
    else {
        return s;
    }
}

/// <summary>
/// Returns the first few characters of the string with a length
/// specified by the given parameter. If the string length is less than the 
/// given length the complete string is returned. If length is zero or 
/// less an empty string is returned
/// </summary>
/// <param name="s">the string to process</param>
/// <param name="length">Number of characters to return</param>
/// <returns></returns>
public static string Left(this string s, int length) {
    length = Math.Max(length, 0);

    if (s.Length > length) {
        return s.Substring(0, length);
    }
    else {
        return s;
    }
}
public static string StripLeft(this string s, int length) {
    length = Math.Max(length, 0);

    if (s.Length > length) {
        return s.Substring(length);
    }
    else {
        return "";
    }
}
public static string StripRight(this string s, int length) {
    length = Math.Max(length, 0);

    if (s.Length > length) {
        return s.Substring(0, s.Length - length);
    }
    else {
        return "";
    }
}
0

, , . , . , . , :

Add(RangeCollection collection2)
  for each int n in collection2.singles
    if n >= infinite_range_start: next n
    // there should only be one infinite range
    for each range r in ranges // ranges should be a sorted list
      if n = r.start - 1
        r.start = n
        next n
      if n = r.end + 1
        r.end = n
        next n
      if n < r.end: break
      if n >= r.start and n <= range.end: next n
    // at this point we know n is not within any ranges
    singles.Add(n) // should be a set
  CheckSinglesForRanges()
  MergeOverlappingRanges()
  CheckInfiniteRange()

CheckSinglesForRanges()
  singleList = singles.ToOrderedList()
  start = null
  end = null
  for each number n in singleList
    if start = null
      start = n
      next n
    if n = start + 1
      end = n
      next n
    if start != null and end != null and end > start + 1
      ranges.Add(new range(start, end))
      start = null
      end = null
  if start != null and end != null and end > start + 1
    ranges.Add(new range(start, end))

MergeOverLappingRanges()
  // ranges should be a list of range objects ordered by range.start
  prevR = null
  for each range r in ranges
    if prevR = null
      prevR = r
      next r
    if prevR.end >= r.start
      prevR.end = r.end
      ranges.Remove(r)
      next r
    prevR = r

CheckInfiniteRange()
  if singles.largest = inifinite_range_start - 1
    inifinite_range_start--
    CheckInfiniteRange()
  if ranges.last.end >= inifinite_range_start - 1
    inifinite_range_start = ranges.last.start
    ranges.remove(ranges.last)
    singles.RemoveAll(where n >= infinite_range_start)
    CheckInfiniteRange()

Subtract(RangeCollection collection2)
  for each number n in collection2.singles
    if singles.Contains(n)
      singles.remove(n)
      next n
    for each range r in ranges
      if n = r.start
        r.start++
        next n
      if n = r.end
        r.end--
        next n
      if n > r.start and n < r.end: 
        if n = r.start + 1
          singles.add(r.start)
          ranges.add(new range(n + 1, r.end))
        if n = r.end - 1
          singles.add(r.end)
          ranges.add(new range(n.start, n - 1))
        else
          ranges.add(new range(r.start, n - 1))
          ranges.add(new range(n + 1, r.end))
        ranges.Remove(r)
        next n
    if n = infinite_range_start
      infinite_range_start++
      next n
    if n = infinite_range_start + 1
      singles.add(infinite_range_start)
      infinite_range_start = n + 1
      next n
    if n > infinite_range_start
      ranges.add(new range(infinite_range_start, n - 1))
      infinite_range_start = n + 1
      next n

:

  • , . , , . .
  • , , . .
  • , , , , .
  • There are a couple of places where a naive implementation will receive a runtime error to remove an item from the list when moving it. This will require your implementation; this should be easy to do.
  • This is stable against negative numbers, except that only an increase in infinite ranges is allowed (transition to positive infinity). For example, “10-” (means moving from 10 to negative infinity) is not a valid range. It is relatively simple to reflect infinite range code if you need this functionality.
-1
source

All Articles