/** return a new set containing all elements in this but not in other. * Intervals may have to be broken up when ranges in this overlap * with ranges in other. other is assumed to be a subset of this; * anything that is in other but not in this will be ignored. * * Keep around, but 10-20-2005, I decided to make complement work w/o * subtract and so then subtract can simply be a&~b */ public IIntSet Subtract(IIntSet other) { if (other == null || !(other is IntervalSet)) { return(null); // nothing in common with null set } IntervalSet diff = new IntervalSet(); // iterate down both interval lists var thisIter = this.intervals.GetEnumerator(); var otherIter = ((IntervalSet)other).intervals.GetEnumerator(); Interval mine = null; Interval theirs = null; if (thisIter.MoveNext()) { mine = (Interval)thisIter.Current; } if (otherIter.MoveNext()) { theirs = (Interval)otherIter.Current; } while (mine != null) { //[email protected]("mine="+mine+", theirs="+theirs); // CASE 1: nothing in theirs removes a chunk from mine if (theirs == null || mine.disjoint(theirs)) { // SUBCASE 1a: finished traversing theirs; keep adding mine now if (theirs == null) { // add everything in mine to difference since theirs done diff.add(mine); mine = null; if (thisIter.MoveNext()) { mine = (Interval)thisIter.Current; } } else { // SUBCASE 1b: mine is completely to the left of theirs // so we can add to difference; move mine, but not theirs if (mine.startsBeforeDisjoint(theirs)) { diff.add(mine); mine = null; if (thisIter.MoveNext()) { mine = (Interval)thisIter.Current; } } // SUBCASE 1c: theirs is completely to the left of mine else { // keep looking in theirs theirs = null; if (otherIter.MoveNext()) { theirs = (Interval)otherIter.Current; } } } } else { // CASE 2: theirs breaks mine into two chunks if (mine.properlyContains(theirs)) { // must add two intervals: stuff to left and stuff to right diff.add(mine.a, theirs.a - 1); // don't actually add stuff to right yet as next 'theirs' // might overlap with it // The stuff to the right might overlap with next "theirs". // so it is considered next Interval right = new Interval(theirs.b + 1, mine.b); mine = right; // move theirs forward theirs = null; if (otherIter.MoveNext()) { theirs = (Interval)otherIter.Current; } } // CASE 3: theirs covers mine; nothing to add to diff else if (theirs.properlyContains(mine)) { // nothing to add, theirs forces removal totally of mine // just move mine looking for an overlapping interval mine = null; if (thisIter.MoveNext()) { mine = (Interval)thisIter.Current; } } // CASE 4: non proper overlap else { // overlap, but not properly contained diff.add(mine.differenceNotProperlyContained(theirs)); // update iterators bool moveTheirs = true; if (mine.startsBeforeNonDisjoint(theirs) || theirs.b > mine.b) { // uh oh, right of theirs extends past right of mine // therefore could overlap with next of mine so don't // move theirs iterator yet moveTheirs = false; } // always move mine mine = null; if (thisIter.MoveNext()) { mine = (Interval)thisIter.Current; } if (moveTheirs) { theirs = null; if (otherIter.MoveNext()) { theirs = (Interval)otherIter.Current; } } } } } return(diff); }