[Question]
  [
Your task here is simple:
Given a list of integer sets, find the set union. In other words, find the shortest list of integer sets that contain all the elements in the original list of sets (but no other elements). For example:
```
[1,5] and [3,9] becomes [1,9] as it contains all of the elements in both [1,5] and [3,9]
[1,3] and [5,9] stays as [1,3] and [5,9], because you don't want to include 4
```
Sets are notated using range notation: `[1,4]` means the integers `1,2,3,4`. Sets can also be unbounded: `[3,]` means all of the integers `>= 3`, and `[,-1]` means all of the integers `<= -1`. It is guaranteed that the first element of the range will not be greater than the second.
You can choose to take sets in string notation, or you can use 2-element tuples, using a constant non-integer as the "infinite" value. You can use two distinct constants to represent the infinite upper bound and the infinite lower bound. For example, in Javascript, you could use `[3,{}]` to notate all integers `>= 3`, as long as you consistently used `{}` across all test cases.
Test cases:
```
[1,3]                     => [1,3]
[1,]                      => [1,]
[,9]                      => [,9]
[,]                       => [,]
[1,3],[4,9]               => [1,9]
[1,5],[8,9]               => [1,5],[8,9]
[1,5],[1,5]               => [1,5]
[1,5],[3,7]               => [1,7]
[-10,7],[1,5]             => [-10,7]
[1,1],[2,2],[3,3]         => [1,3]
[3,7],[1,5]               => [1,7]
[1,4],[8,]                => [1,4],[8,]
[1,4],[-1,]               => [-1,]
[1,4],[,5]                => [,5]
[1,4],[,-10]              => [1,4],[,-10]
[1,4],[,]                 => [,]
[1,4],[3,7],[8,9],[11,20] => [1,9],[11,20]
```
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so make your answer as short as possible!
  
[Answer]
# [R](https://www.r-project.org/) + `intervals`, ~~90 87~~ 81 bytes
```
function(...)t(reduce(Intervals(rbind(...),type="Z")))+c(1,-1)
library(intervals)
```
[Try it online!](https://tio.run/##bY9NDoIwEIX3nMKw6sQpsYBREz0AV3AHpZAmpJpaTDh9bflRBFZ9/d68zqu29e5KbdUqbuRDkSiKwBAtypYLkikj9DtvXkQXUpW9iaZ7ilt4DwFgzwlDyiBoZKFz3RE5BcDWxJsJQDCoTFWjpk7iZX75eT6BnKRfn@HRg/MS@OMPJHianmQHpxczzIMY42F0qpWsB9Nh3bxSjyjbYL78cYO5Cht0lR/X@8/5FgxjF7Mf "R – Try It Online")
Input is a list of intervals. `-Inf` and `Inf` are R built-ins for minus/plus infinity. Output is a matrix of columns of intervals.
Not usually a fan of using non-standard libraries but this one was fun. TIO doesn't have `intervals` installed. You can try it on your own installation or at <https://rdrr.io/snippets/> 
The `intervals` package supports real and integer (`type = "Z"`) intervals and the `reduce` function is a built-in for what the challenge wants, but the output seems to default to open intervals, so ~~`close_intervals`~~ `+c(1,-1)` is needed to get the desired result.
[Old version had examples in list of lists](https://tio.run/##dZDNCoMwEITvPoV4ysIKjT@0hfYBvPbYS9EYIRCiRC369NY0RdTGS8J8mdlMoqfKv4VT1SvWiVqRAZisW/4SquP6ncuWaF72jJNsAQ8LdCFUiQNgNzb8HjwDAPCkKHSuR7LEYZJ508iRSNF2dmGEYgyA3qIyVa10OEu87sHWYyYgI8nGRzE18OKCZvuDMZ7X19DTrB1eamCEkY2sq8fuQGJr7Ct/cUgPuHlkesDnagcnzlm/WuYjTDuK0RwH9CuYPg "R – Try It Online") which might be convenient so I've left the link here.
[Answer]
# JavaScript (ES6), 103 bytes
*Saved 1 byte thanks to @Shaggy*  
*Saved 1 byte thanks to @KevinCruijssen*
Expects `+/-Infinity` for infinite values.
```
a=>(a.sort(([p],[P])=>p-P).map(m=M=([p,q])=>p<M+2?M=q>M?q:M:(b.push([m,M]),m=p,M=q),b=[]),b[0]=[m,M],b)
```
[Try it online!](https://tio.run/##hZLLboMwEEX3/QqWtjKQ8IjSRDVZd2Epe8sLSEJLFV6BVurXU8eUloeNWVhiZg53uL4f0VdUn@9p2dh5cbm2CWkjEqLIqYt7gxArObATxyQs7RN2sqhEGaFE1KGS1Re68o6UVCE9Vgd6QLFTftbviGVAOYaMlCCaGGLCxGvMNpzIFsS4PRd5Xdyuzq14QwlizAWfW8qHY2yt1xYJLTn0NCdXr3mS5mnzzRfIOWj3GOz1oOgtgFPlIaja1BeGBjO5yaZ7FbkV5LOJ7Ic0/OM08BrSh90yuVO45G5EWaU6ILshhaorSA88qT1MhikNvkbTvK8LgbRvnqYR2Q3pcFuRxtHv6sm/UG1Vwuq7GYPCTK7ZWPaMH/hf3RTk4DcUXd6E4S54D/FJkPtG@wM "JavaScript (Node.js) – Try It Online")
### How?
We first sort the intervals by their lower bound, from lowest to highest. Upper bounds are ignored.
We then iterate over the sorted intervals \$[p\_n,q\_n]\$, while keeping track of the current lower and upper bounds \$m\$ and \$M\$, initialized to \$p\_1\$ and \$q\_1\$ respectively.
For each interval \$[p\_n,q\_n]\$:
* If \$p\_n\le M+1\$: this interval can be merged with the previous ones. But we may have a new upper bound, so we update \$M\$ to \$\max(M,q\_n)\$.
* Otherwise: there is a gap between the previous intervals and this one. We create a new interval \$[m,M]\$ and update \$m\$ and \$M\$ to \$p\_n\$ and \$q\_n\$ respectively.
At the end of the process, we create a last interval with the current bounds \$[m,M]\$.
### Commented
```
a => (                  // a[] = input array
  a.sort(([p], [P]) =>  // sort the intervals by their lower bound; we do not care about
    p - P)              // the upper bounds for now
  .map(m = M =          // initialize m and M to non-numeric values
    ([p, q]) =>         // for each interval [p, q] in a[]:
    p < M + 2 ?         //   if M is a number and p is less than or equal to M + 1:
      M = q > M ? q : M //     update the maximum M to max(M, q)
    : (                 //   else (we've found a gap, or this is the 1st iteration):
      b.push([m, M]),   //     push the interval [m, M] in b[]
      m = p,            //     update the minimum m to p
      M = q             //     update the maximum M to q
    ),                  //
    b = []              //   start with b[] = empty array
  ),                    // end of map()
  b[0] = [m, M], b      // overwrite the 1st entry of b[] with the last interval [m, M]
)                       // and return the final result
```
[Answer]
# [Python 2](https://docs.python.org/2/), ~~118~~ ~~113~~ ~~112~~ ~~111~~ ~~106~~ ~~105~~ ~~104~~ 101 bytes
```
x=input()
x.sort();a=[];b,c=x[0]
for l,r in x:
 if l>c+1:a+=(b,c),;b,c=l,r
 c=max(c,r)
print[(b,c)]+a
```
Saved one byte thanks to Mr.Xcoder, one thanks to Jonathan Frech, and three thanks to Dead Possum.  
[Try it online!](https://tio.run/##fZBRb4MgFIXf@RU3vhQmLkXbdG3D/ojxgTFNSRwY6hL26x3c2WRxziduvnMu58DwNd6cLSft3luQkGXZFKSxw@dIGQnPd@fjcFWybq5vXMtQ7xvSOQ8992AshAsB00H/qnNxUbmk0cQ4WqODgJYfKlDNPSODN3as0dDkaopJhLSh1ZCin8RpqqngULGG4ND1To10Z2y3Y8hmUCDhcF6Df5bwRg708FiI4JjAyxLg@RtUHE4ICrFP48IjEig5lLP3p3i14jzMeWvlUCvEhrh44XFLjE235H8zHq3xU1L7KJTxqm8 "Python 2 – Try It Online")
[Answer]
# [Ruby](https://www.ruby-lang.org/), ~~89~~ 76 bytes
```
->a{[*a.sort.reduce{|s,y|s+=y;y[0]-s[-3]<2&&s[-3,3]=s.max;s}.each_slice(2)]}
```
[Try it online!](https://tio.run/##RY5NC4JAGITv/gpP0cfr4ielZkfBi6cu8bLEZisFhuIquKi/3dY@b/PMDMzU7UVOeTQZB9bjmhFR1g2p@bXNeD8IkIPYRDKUaFJDoOHQvb1YzAIcGgnyYF0oRsJZdjuL4p7xpb2i44SIlipQ0BDjomRNECRpnKTJ8QS6//bnAqALP/QU7v7oKnRg@zEBLQts8xv6r9CjVKPqQ9UP3VDpOXZq@wk "Ruby – Try It Online")
Sort the array, then flatten by appending all the ranges to the first: if a range overlaps the previous one, discard 2 elements from the last 3 (keeping only the max).
Unflatten everything at the end.
[Answer]
# [Stax](https://github.com/tomtheisen/stax), ~~46~~ ~~39~~ 38 [bytes](https://github.com/tomtheisen/stax/blob/master/docs/packed.md#packed-stax)
```
├&P◙╛╛ΘΩ¿σa○♦◘♣┐¬≥∩ó¬îî◙k]∙♣•╘○π≡¡jN<♀
```
[Run and debug it](https://staxlang.xyz/#p=c326500abebee9eaa8e56109040805bfaaf2efa2aa8c8c0a6b5df90507d409e3f0ad6a4e3c0c&i=%22%5B1,3%5D,%5B2,4%5D,%5B4,6%5D,%5B7,9%5D,%5B11,13%5D%22%0A%22%5B1,3%5D%22%0A%22%5B1,%5D%22%0A%22%5B,9%5D%22%0A%22%5B,%5D%22%0A%22%5B1,3%5D,%5B4,9%5D%22%0A%22%5B1,5%5D,%5B8,9%5D%22%0A%22%5B1,5%5D,%5B1,5%5D%22%0A%22%5B1,5%5D,%5B3,7%5D%22%0A%22%5B-10,7%5D,%5B1,5%5D%22%0A%22%5B1,1%5D,%5B2,2%5D,%5B3,3%5D%22%0A%22%5B3,7%5D,%5B1,5%5D%22%0A%22%5B1,4%5D,%5B8,%5D%22%0A%22%5B1,4%5D,%5B-1,%5D%22%0A%22%5B1,4%5D,%5B,5%5D%22%0A%22%5B1,4%5D,%5B,-10%5D%22%0A%22%5B1,4%5D,%5B,%5D%22%0A%22%5B1,4%5D,%5B3,7%5D,%5B8,9%5D,%5B11,20%5D%22&a=1&m=2)
This program takes input in the originally specified string notation.
[Answer]
# [Pascal (FPC)](https://www.freepascal.org/), ~~367~~ ~~362~~ 357 bytes
```
uses math;type r=record a,b:real end;procedure d(a:array of r);var i,j:word;t:r;begin for i:=0to length(a)-1do for j:=0to i do if a[i].a<a[j].a then begin t:=a[i];a[i]:=a[j];a[j]:=t;end;j:=0;for i:=1to length(a)-1do if a[j].b>=a[i].a-1then begin a[j].a:=min(a[i].a,a[j].a);a[j].b:=max(a[i].b,a[j].b)end else j:=j+1;for i:=0to j do writeln(a[i].a,a[i].b)end;
```
[Try it online!](https://tio.run/##ZVLBcoIwEL33K/ZWmAYxqOOUlN56661Hp4cNRA1DwYao9evtJqGI04vJ27f73ubhAfsSm2R7KK/XY696@EK7F/ZyUGAKo8rOVIBM5kZhA6qtxMF0paqORkEVYY7G4AW6LZhYnNCAZnV@phlhcyOk2ukWth2V82JuO2hUu7P7COOEV50n6kBoIKy3gBv9OcMX3NR0gN2rFoKIzQvHCffjrrW71nS1wi3lZMRgxP8ZeWFSlK9FMEj4RDqY5cWXbqNAs1CKRZgiCn8CJQMlYzIF1fTKPaB@4mLyyNq95Wy0Vc1EUA9T4pqmb9/Hkz4hLWmht2h1CT7HHh7S1KU45LqZz2b806eL7U4VUcTZOmbRgj3HsRh65a03u@vN2IJ6kyVb0bFiPJ27oYm8bw4VeVfxuTwAfCj7PgTJMpoFymrus@IjoHTWAXDPLEZAzLMDf1E8Yv7oReh/E08IceckaWtXkYNTNgI5guC0HAExqwAyz9wAMfTuuy3kuIWkk77I7PoL "Pascal (FPC) – Try It Online")
A procedure that takes a [dynamic array](https://www.freepascal.org/docs-html/ref/refsu14.html#x38-510003.3.1) of records consisting of 2 range bounds, modifies the array in place and then writes it on standard output, one range per line. (Sorry for that twisted sentence.) Uses `1/0` for ubounded up and `-1/0` for unbounded down.
[Readable version](https://tio.run/##dVNNj5swEL3zK@a2oBIMyaarwKKeeuutx2gPY3CCEcGu7exH/3w62AlJdlULyXpvxjNvPtBoGxwWO92cTkcrLBzQdVXkPrQAg@Ne1EY0yrQR@IMpL43AIUAxtlWkjWpEezQC2hhLNAY/QO3C46SKXtGATPvyjYJUrvR0FXGxlyMF2SmylnUOTsEgxr3rYkwWBbTKZ5jM/dksLySA3AFu5UuGz7jt6QLXiREuMcNxZT35VDMxoYnr77ieOHchfD3gM1ZXccV/xM0qFsWzj5vxGyHA2EGYvYiumTIs64Mc4/AqDVRS3Xpw8sD34MGDB0@is7ZwD1ZMCvtvxfSSsd/C/TqLS4lMiBqVA62slXwQsAAEaUFpUham0wkz0Z1zumSMqjwesgH/ojnabGeE0H4nMmX2TI6teM90p384pWVTb/LV9yz3ea0CbeToQNI3Wiew/TTQnjoFb0Y6MdwULX1JU6tPjP38c3yVr0jddWAdOtkEjRYixqbVOW/UNs@y4mXeqzqOi/QpSeNVukmog8GXX32Xd77LdEW@i8d0Tdc6LVienDfz88IGln9hL7t12@ylHx1ucz/YYgY0w6cACm9ZzYAsmwlcevKA5YMPQn9OcmOo7jJxUj8x/JxpOQM@g5DpcQZkWQew9JYrIAvVf6eCzyo43TSZ7PQP)
It would be nice to just return the array with corrected number of elements, but the dynamic array passed to function/procedure is not dynamic array anymore... First I found [this](http://forum.lazarus.freepascal.org/index.php?topic=9036.0), then there is this [excellent, mind-boggling explanation](http://rvelthuis.de/articles/articles-openarr.html).
This is the best data structure I could found for shortening the code. If you have better options, feel free to make a suggestion.
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), 57 bytes
```
List@@(#-{0,1}&/@IntervalUnion@@(Interval[#+{0,1}]&/@#))&
```
[Try it online!](https://tio.run/##dYxfC4IwFMW/ijCQpCu6NKo3IQiEgl56Eh9GKA3cXawVxNhnX1fLx97On985Sthbp4SVVxHORqJtTuLehKN82KpasNTlwH2cVTXazrzEcEGpkZrZN2w5IS0xLEniAC5yjkPhPZBIa@wlSvuGWXzzEQBXwu6H8Rw2FHBYz31J9v96bItpsqUPGnJY5d5Hvs2yvR6eCg/aqDZ8AA "Wolfram Language (Mathematica) – Try It Online")
Takes input as a list of lists `{a,b}` representing the interval `[a,b]`, where `a` can be `-Infinity` and `b` can be `Infinity`.
Uses the built-in `IntervalUnion`, but of course we have to massage the intervals into shape first. To pretend that the intervals are integers, we add 1 to the upper bound (making sure that the union of `[1,3]` and `[4,9]` is `[1,9]`). At the end, we undo this operation, and turn the result back into a list of lists.
There's also a completely different approach, which clocks in at **73 bytes**:
```
NumericalSort@#//.{x___,{a_,b_},{c_,d_},y___}/;b+1>=c:>{x,{a,b~Max~d},y}&
```
Here, after sorting the intervals, we just replace two consecutive intervals by their union whenever that would be a single interval, and repeat until there is no such operation left to be done.
[Answer]
# [05AB1E (legacy)](https://github.com/Adriandmen/05AB1E/wiki/Commands), ~~88~~ ~~79~~ 78 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
g≠i˜AKïDW<UZ>VIøεAXY‚Nè:}ïø{©˜¦2ôíÆ1›.œʒíεćsO_*}P}н€g®£εø©θàDYQiA}V®нßDXQiA}Y‚
```
Infinity is input as the lowercase alphabet (`'abcdefghijklmnopqrstuvwxyz'`).
[Try it online](https://tio.run/##MzBNTDJM/f8//VHngszTcxy9D693CbcJjbIL8zy849xWx4jIRw2z/A6vsKo9vP7wjupDK0/PObTM6PCWw2sPtxk@atild3TyqUmH157beqS92D9eqzag9sLeR01r0g@tO7T43NbDOw6tPLfj8AKXyMBMx9qwQ@su7D083yUCxAGZ@/9/dLShjkmsTrRSYlJySmpaekZmVnZObl5@QWFRcUlpWXlFZZWSjq4pUIWxjjmItNAxMQDSFjqWQNLQUMcIxDMy1cFnAEilqY6RcWwsAA) or [verify all test cases](https://tio.run/##MzBNTDJM/V9Waa@k8KhtkoKSfaXL//RHnQsyT89x9D683iXcJjTKLqzy8I5zWx0jIh81zPI7vMKq9vD6wzuqD608PefQMqPDWw6vPdxm@Khhl97RyacmHV57buuR9mL/eK3agNoLex81rUk/tO7Q4nNbD@84tPLcjsMLXCIDMx1rww6tu7D38HyXCBAHZO7/2sOrK2t1/kdHRxvqGMfG6igogFjqiUnJKalp6RmZWdk5uXn5BYVFxSWlZeUVlVXqUEX4lOhYEqOICEtAbtKJNoGbZ6hjCuRboPFBJDLfWMccytc1NACyUVUYAvlGOkZgdTAfG2OoMgHbQ8iJMJW6hsT5BqQWb5iYEq8U6DfiFRPtOkhIgEIYGB6GOkYk2KFrCtdvbKFjYoBmDjDUTfG7A6jSVMcIGCexAA).
**Important note:** If there was an actual `Infinity` and `-Infinity`, it would have been **~~43~~ 42 bytes** instead. So ~~little over 50%~~ around 30% is as work-around for the lack of `Infinity`..
```
{©Dg≠i˜¦2ôíÆ1›.œʒíεćsO_*}P}н€g®£εø©θàV®нßY‚
```
[Try it online](https://tio.run/##MzBNTDJM/f8//VHngszqQytPzzm0zOjwlsNrD7cZPmrYpXd08qlJh9ee23qkvdg/Xqs2oPbC3kdNa9IPrTu0@NzWwzsOrTy34/CCsEPrLuw9PD/yUcOs//@jow11TGJ1onUt4UBH1xQoYKxjDiItdEwMgLSFjiWQNDTUMQLxjEx1EMpB4qY6RsaxsQA) (with `Infinity` replaced with `9999999999` and `-Infinity` replaced with `-9999999999`).
Can definitely be golfed substantially. In the end it turned out very, very ugly full of workarounds. But for now I'm just glad it's working.
**Explanation:**
```
Dg≠i          # If the length of the implicit input is NOT 1:
              #   i.e. [[1,3]] → length 1 → 0 (falsey)
              #   i.e. [[1,4],["a..z",-5],[3,7],[38,40],[8,9],[11,20],[25,"a..z"],[15,23]]
              #    → length 8 → 1 (truthy)
    ˜         #  Take the input implicit again, and flatten it
              #   i.e. [[1,4],["a..z",-5],[3,7],[38,40],[8,9],[11,20],[25,"a..z"],[15,23]]
              #    → [1,4,"a..z",-5,3,7,38,40,8,9,11,20,25,"a..z",15,23]
     AK       #  Remove the alphabet
              #   i.e. [1,4,"a..z",-5,3,7,38,40,8,9,11,20,25,"a..z",15,23]
              #    → ['1','4','-5','3','7','38','40','8','9','11','20','25','15','23']
       ï      #  Cast everything to an integer, because `K` turns them into strings..
              #   i.e. ['1','4','-5','3','7','38','40','8','9','11','20','25','15','23']
              #    → [1,4,-5,3,7,38,40,8,9,11,20,25,15,23]
        D     #  Duplicate it
         W<   #  Determine the min - 1
              #   i.e. [1,4,-5,3,7,38,40,8,9,11,20,25,15,23] → -5
           U  #  Pop and store it in variable `X`
         Z>   #  Determine the max + 1
              #   i.e. [1,4,-5,3,7,38,40,8,9,11,20,25,15,23] → 40
           V  #  Pop and store it in variable `Y`
Iø            #  Take the input again, and transpose/zip it (swapping rows and columns)
              #   i.e. [[1,4],["a..z",-5],[3,7],[38,40],[8,9],[11,20],[25,"a..z"],[15,23]]
              #    → [[1,'a..z',3,38,8,11,25,15],[4,-5,7,40,9,20,'a..z',23]]
  ε       }   #  Map both to:
   A          #   Push the lowercase alphabet
    XY‚       #   Push variables `X` and `Y`, and pair them into a list
       Nè     #   Index into this list, based on the index of the mapping
         :    #   Replace every alphabet with this min-1 or max+1
              #   i.e. [[1,'a..z',3,38,8,11,25,15],[4,-5,7,40,9,20,'a..z',23]]
              #    → [['1','-6','3','38','8','11','25','15'],['4','-5','7','40','9','20','41','23']]
ï             #  Cast everything to integers again, because `:` turns them into strings..
              #   i.e. [['1','-6','3','38','8','11','25','15'],['4','-5','7','40','9','20','41','23']]
              #    → [[1,-6,3,38,8,11,25,15],[4,-5,7,40,9,20,41,23]]
 ø            #  Now zip/transpose back again
              #   i.e. [[1,-6,3,38,8,11,25,15],[4,-5,7,40,9,20,41,23]]
              #    → [[1,4],[-6,-5],[3,7],[38,40],[8,9],[11,20],[25,41],[15,23]]
  {           #  Sort the pairs based on their lower range (the first number)
              #   i.e. [[1,4],[-6,-5],[3,7],[38,40],[8,9],[11,20],[25,41],[15,23]]
              #    → [[-6,-5],[1,4],[3,7],[8,9],[11,20],[15,23],[25,41],[38,40]]
   ©          #  Store it in the register (without popping)
˜             #  Flatten the list
              #   i.e. [[-6,-5],[1,4],[3,7],[8,9],[11,20],[15,23],[25,41],[38,40]]
              #    → [-6,-5,1,4,3,7,8,9,11,20,15,23,25,41,38,40]
 ¦            #  And remove the first item
              #   i.e. [-6,-5,1,4,3,7,8,9,11,20,15,23,25,41,38,40]
              #    → [-5,1,4,3,7,8,9,11,20,15,23,25,41,38,40]
  2ô          #  Then pair every two elements together
              #   i.e. [-5,1,4,3,7,8,9,11,20,15,23,25,41,38,40]
              #    → [[-5,1],[4,3],[7,8],[9,11],[20,15],[23,25],[41,38],[40]]
    í         #  Reverse each pair
              #   i.e. [[-5,1],[4,3],[7,8],[9,11],[20,15],[23,25],[41,38],[40]]
              #    → [[1,-5],[3,4],[8,7],[11,9],[15,20],[25,23],[38,41],[40]]
     Æ        #  Take the difference of each pair (by subtracting)
              #   i.e. [[1,-5],[3,4],[8,7],[11,9],[15,20],[25,23],[38,41],[40]]
              #    → [6,-1,1,2,-5,2,-3,40]
      1›      #  Determine for each if they're larger than 1
              #   i.e. [6,-1,1,2,-5,2,-3,40] → [1,0,0,1,0,1,0,1]
.œ            #  Create every possible partition of these values
              #   i.e. [1,0,0,1,0,1,0,1] → [[[1],[0],[0],[1],[0],[1],[0],[1]],
              #                             [[1],[0],[0],[1],[0],[1],[0,1]],
              #                             ...,
              #                             [[1,0,0,1,0,1,0],[1]],
              #                             [[1,0,0,1,0,1,0,1]]]
  ʒ         } #  Filter the partitions by:
   í          #   Reverse each inner partition
              #    i.e. [[1],[0,0,1],[0,1],[0,1]] → [[1],[1,0,0],[1,0],[1,0]]
    ε     }   #   Map each partition to:
     ć        #    Head extracted
              #     i.e. [1,0,0] → [0,0] and 1
              #     i.e. [1] → [] and 1
              #     i.e. [1,0,1] → [1,0] and 1
      s       #    Swap so the rest of the list is at the top of the stack again
       O      #    Take its sum
              #     i.e. [0,0] → 0
              #     i.e. [] → 0
              #     i.e. [1,0] → 1
        _     #    And check if it's exactly 0
              #     i.e. 0 → 1 (truthy)
              #     i.e. 1 → 0 (falsey)
         *    #    And multiply it with the extracted head
              #    (is only 1 when the partition has a single trailing 1 and everything else a 0)
              #     i.e. 1 and 1 → 1 (truthy)
              #     i.e. 1 and 0 → 0 (falsey)
           P  #   And check if all mapped partitions are 1
н             #  Take the head (there should only be one valid partition left)
              #   i.e. [[[1],[0,0,1],[0,1],[0,1]]] → [[1],[0,0,1],[0,1],[0,1]]
 €g           #  Take the length of each inner list
              #   i.e. [[1],[0,0,1],[0,1],[0,1]] → [1,3,2,2]
   ®          #  Push the sorted pairs we've saved in the register earlier
    £         #  Split the pairs into sizes equal to the partition-lengths
              #   i.e. [1,3,2,2] and [[-6,-5],[1,4],[3,7],[8,9],[11,20],[15,23],[25,41],[38,40]]
              #    → [[[-6,-5]],[[1,4],[3,7],[8,9]],[[11,20],[15,23]],[[25,41],[38,40]]]
ε             #  Map each list of pairs to:
 ø            #   Zip/transpose (swapping rows and columns)
              #    i.e. [[1,4],[3,7],[8,9]] → [[1,3,8],[4,7,9]]
              #    i.e. [[25,41],[38,40]] → [[25,38],[41,40]]
  ©           #   Store it in the register
   θ          #   Take the last list (the ending ranges)
              #    i.e. [[25,38],[41,40]] → [41,40]
    à         #   And determine the max
              #    i.e. [41,40] → 41
     DYQi }   #   If this max is equal to variable `Y`
              #     i.e. 41 (`Y` = 41) → 1 (truthy)
         A    #    Replace it back to the lowercase alphabet
           V  #   Store this max in variable `Y`
  ®           #   Take the zipped list from the register again
   н          #   This time take the first list (the starting ranges)
              #    i.e. [[25,38],[41,40]] → [25,38]
    ß         #   And determine the min
              #    i.e. [25,38] → 25
     DXQi }   #   If this min is equal to variable `X`
              #     i.e. 25 (`X` = -6) → 0 (falsey)
         A    #    Replace it back to the lowercase alphabet
           Y‚ #   And pair it up with variable `Y` (the max) to complete the mapping
              #    i.e. 25 and 'a..z' → [25,'a..z']
              #  Implicitly close the mapping (and output the result)
              #   i.e. [[[-6,-5]],[[1,4],[3,7],[8,9]],[[11,20],[15,23]],[[25,41],[38,40]]]
              #    → [['a..z',-5],[1,9],[11,23],[25,'a..z']]
              # Implicit else (only one pair in the input):
              #  Output the (implicit) input as is
              #   i.e. [[1,3]]
```
[Answer]
# [C (clang)](http://clang.llvm.org/), ~~346~~ 342 bytes
Compiler flags `-DP=printf("(%d,%d)\n"`,`-DB=a[i+1]`, and `-DA=a[i]`
```
typedef struct{int a,b;}t;s(t**x,t**y){if((*x)->a>(*y)->a)return 1;else if((*x)->a<(*y)->a)return -1;}i;f(t**a){for(i=0;A;)i++;qsort(a,i,sizeof(t*),s);for(i=0;B;i++){if(B->a<=A->b+1){A->b=B->b;if(B->a<A->a)A->a=B->a;else B->a=A->a;}}for(i=0;A;i++){if(!B)break;if(A->a!=B->a)P,A->a,A->b);}P,A->a,A->b);}
```
[Try it online!](https://tio.run/##XZDLboMwEEX3fIWDlMoDRoImVR9TIoH6AdmnLMwrsppCip0qKeLXSz1USdRu5nF8587IRVDsZLMdR3PaV2VVM226Q2F61RgmRY6DQc2N5x2FDSfoVc25d4RgJVfc9jZDV5lD17AIq52u2FXw/E8QRDgorMlNQl@3HVdxiAmC8n380G1nuBRKaPVVtaQCoQHPshStalqfknWcBKvcj6CnHFuU4/kpoZUUCMvfo6iiEYnDcF18dpylkHeVfCMLEs2mSVgLaijkgMPfbqT/eZeq4dA7hnlyc5ehIzdhxmJ2ww30kVgORKILWYj7idxeyIN4nMjiOhWJ23BiS2L8s1WlByE6@4PR3K25hCcX0KECnWH8Luqd3OoxeFnH@84eVXOXz0sxL@G1cS1OY7lRfpTZMqEy@wE "C (clang) – Try It Online")
]