# Detect the intersection of multiple ranges in JavaScript

Published on Monday, June 20, 2022

Recently, while working on a feature for Octo, I had to figure out how to test the intersection of multiple ranges using JavaScript. Specifically, I needed to come up with a performant solution to detect when any text-selection ranges intersected with specific syntax node ranges in the editor. This was a fun problem to work on, so I hope you like the solution.

### How to compare ranges

A range can reasonably be represented by a starting point and an ending point. For the purpose of this post, we will assume the starting point is the **minimum** and the ending point is the **maximum**.

We will know multiple ranges are intersecting when the **maximal minimum** (the largest starting point) of the ranges is *less than or equal to* the **minimal maximum** (the smallest ending point). We can make this abstract concept a little more concrete by plotting two ranges on a number line.

` [0, 1, 2, 3, 4]//--0--1--2--3--4--5--6--7--8--9---> [2, 3, 4, 5, 6]`

The minimums of the ranges are `[0, 2]`

, and the maximums of the ranges are `[4, 6]`

. The *maximal* value of the minimums is `2`

, and the *minimal* value of the maximums is `4`

. Since `2`

is *less than or equal to* `4`

, we can safely say the two ranges intersect.

## Detect the intersection of **all** ranges

For these examples, we will use the following `range`

function.

`type NumberRange = { min: number, max: number }const range = (min: number, max: number): NumberRange => { return { min, max }}`

The method we learned above works for any number of ranges as along as you want to assert that *all* of the ranges intersect (more on that later). We can implement the logic from the previous example as a function that accepts any number of ranges.

`const allIntersect = (...ranges: NumberRange[]) => { // Create separate arrays for the min and max values. const minimums = ranges.map(r => r.min) const maximums = ranges.map(r => r.max) // Extract the comparands. const maximalMinimum = Math.max(...minimums) const minimalMaximum = Math.min(...maximums) return maximalMinimum <= minimalMaximum}`

Then, we can use this function to detect whether the given ranges are intersecting.

`allIntersect(range(0, 4), range(2, 6), range(4, 8))// trueallIntersect(range(0, 4), range(2, 6), range(10, 14))// false`

## Detect the intersection of **some** ranges

The implementation above works well for checking whether *all* of the ranges intersect, but it is sometimes necessary to check whether *some* of the ranges intersect. We can create another function for that purpose which builds upon our original solution.

`const someIntersect = (...ranges: NumberRange[]) => { return ranges.some((range1, index1) => { // Compare all ranges to all other ranges. return ranges.some((range2, index2) => { // Do not compare a range to itself. if (index1 === index2) { return false } return allIntersect(range1, range2) }) })}`

`someIntersect(range(0, 4), range(2, 6), range(4, 8))// truesomeIntersect(range(0, 4), range(2, 6), range(10, 14))// truesomeIntersect(range(0, 4), range(10, 14))// false`

This one might be a bit niche, but I would love to hear about your own use case. If you found this post helpful, you want to know more, you have a question, or you just want to say hi, please leave a comment down below!

Thanks for reading, and happy coding. ✌️