I would
- Keep an unordered list of "open" ranges
- Start from day 1, and add the first range to the open ranges list.
- Move until the next range boundary (be it start or close). Create your first "output" range: starting from day 1, ending on that day. In it are the items in your open ranges list.
- If the range encountered is already in the open ranges list, remove it. Otherwise, add it.
- Repeat 3 and 4, moving along the line.
I definitely did a bad job of explaining it. I'll be writing some code for this soon. But until then, here's what would happen in your solution:
a |------------------------------|
b |-------------------|
c |-----------------|
1. Start at day 1, add A to open ranges list, which now contains [A]
2. Move to the start of C. First RESULT RANGE: A range from Day 1 to C's start,
with a value A. (what is in your open ranges list)
3. Add C to the open ranges list, which now contains [A,C]
4. Move to the start of B. Second RESULT RANGE: A range from C's start to B's
start, with a value A,C. (what is in your open ranges list)
5. Add B to the open ranges list, which now contains [A,C,B]
6. Move to the end of C. Third RESULT RANGE: A range from B's start to C's end,
with a value of A,C,B.
7. Remove C from the open ranges list, which now contains [A,B]
8. Move to the end of A. Fourth RESULT RANGE: A range from C's end to A's end,
with a value of A,B
9. Remove A from the open ranges list, which now contains [B]
10. Move to the end of A. Fourth RESULT RANGE: A range from A's end to B's end,
with a value of B
RESULT RANGES
1. from Day 1 to C's start: A
2. from C's start to B's start: A,C
3. from B's start to C's end: A,C,B
4. from C's end to A's end: A,B
5. from A's end to B's end: B
Alternative Method
You could do this:
- Keep a ordered list of "output ranges". This makes it easy to test if a point is within a range, and also what ranges follow eachother.
- Take a range from your input ranges.
- Check to see if it is completely before or completely after all output ranges, and handle accordingly. Skip the next steps and go back to step 2, if so.
- Compare its start point to the output ranges
- If it is before any other output range, add a new output range from its start to the start of the first output range.
- If this is in between an already-existing output range, split that output range at that point. The first part would hold the same "parents", and the second part would have the same parents + the new input range.
- Now, compare its end point to the output ranges.
- If it is after any other output range, add a new output range from the end of the last output range to its end.
- If this is in between an already-existing output range, split that output range at that point. The second part would hold the same "parents", and the first part would have the same parents + the new input range
- Add the current input range as a part to all ranges in between the two "processed" ranges in steps 6 and 9, if any.
- Repeat 2-6 for all input ranges.
Here are the first few steps, using the sample data + another range D:
("processed" ranges indicated by **double stars**
)
a |------------------------------|
b |-------------------|
c |-----------------|
d |------------------------|
1.
Process A
Output ranges: |--------------A---------------|
2.
Process B
- Start of B is in **A**; split A in two:
|-------A-------|------AB------|
- End of B is after any output range range;
creating new output range at end
|-------A-------|------AB------|---B---|
- Nothing was/is in between **A** and (nothing)
3.
Process C
- Start of C is in **A**; split A in two:
|---A----|--AC--|------AB------|---B---|
- End of C is in **AB**; split AB in two:
|---A----|--AC--|--ABC--|--AB--|---B---|
- There were/are no ranges between **A** and **AB**
4.
Process D
- Start of D is in **A**; split A in two:
|-A-|-AD-|--AC--|--ABC--|--AB--|---B---|
- End of D is in **AB**; split AB in two:
|-A-|-AD-|--AC--|--ABC--|ABD|AB|---B---|
- Ranges AC and ABC were/are in between **A** and **AB**
|-A-|-AD-|--ACD-|-ABCD--|ABD|AB|---B---|
Final output: |-A-|-AD-|--ACD-|-ABCD--|ABD|AB|---B---|