npm package: @scotttrinh/number-ranges
Description: Interact with sets of natural numbers and convert to range strings
Author: Scott Trinh
Latest version: 2.1.0

# Number Ranges

Data structure for working with sets of numbers and serializing as range strings.

## Examples

```js
import NumberRanges from '@scotttrinh/number-ranges';

// Constructor
// With Array
var myRange = new NumberRanges([0, 1, 2, 3, 5, 6]);
// With { start, end } object
var myExplicitRange = new NumberRanges({ start: 0, end: 3 });
// With NumberRanges
var myNumberRangesRange = new NumberRanges(myExplicitRange);


// String/JSON representation
console.log(myRange); // 0-3,5-6
console.log(myRange.toString()); // '0-3,5-6'
console.log(JSON.stringify({ range: myRange })); // {"range":"0-3,5-6"}

// Add items to the set
myRange.add([4]);
myRange.add([4]);
myRange.add([4]);
myRange.add(new Set([4])); // Works for TypedArray and ES2015 Set

console.log(myRange); // 0-6

var sixToTwelve = new NumberRanges({ start: 6, end: 12 });
myRange.union(sixToTwelve);
console.log(myRange); // 0-12

// Remove items from the set
myRange.remove([4, 1, 6]);

console.log(myRange); // 0-0,2-3,5-5

// Check for set membership
console.log(myRange.contains(2)); // true
console.log(myRange.contains(4)); // false

// Alternate Serializer
var alternateSerializer = function alternateSerializer(ranges) {
    return ranges
        .map(function (range) {
            return '' + range[0] + ':'
        })
        .join('###');
}
var mySpecialRange = new NumberRanges([0, 1, 2, 3, 5, 6], { serializer: alternateSerializer });

console.log(mySpecialRange.toString()); // '0:3###5:6'

// Convert back to Array of (sorted) numbers
console.log(myRange.toArray()); // [0, 1, 2, 3, 5, 6]

// Find min/max
myRange.min(); // 0
myRange.max(); // 6
```

## Constructor

### `NumberRanges: (Iterable<number> | NumberRanges | { start: number, end: number }) => void`

- `input: Iterable<number> | NumberRanges | { start: number, end: number }`
  Numbers to add to the new NumberRanges object
- `config`
  - `config.serializer: (ranges: Array<number, number>) => string`
    A function that receives an array of `[start, end]` pairs and should return
    a string. Is used for `toString()` and `toJSON()`.

Constructor function that takes an `Iterable<number>`, existing
`NumberRanges` object, or `{ start: number, end: number }` object literal and
returns a `NumberRanges` object representing the range of numbers passed. Has an
optional `config` object that you can pass a serializer object. See `toString()`
and `toJSON()`.

```js
const missingBytes = new NumberRanges([0, 1, 2, 3, 4, 5]); // 0-5
const selectedProducts = new NumberRanges(new Set([0, 1, 1, 1, 2, 3, 3, 3])); // 0-3
const favoriteNumbers = new NumberRanges({ start: 0, end: 42 }); // 0-42
const rangesInception = new NumberRanges(new NumberRanges([42])); // 42
```

## Properties

### `NumberRanges.ranges: Array<number, number>`

If you would like to interact with the ranges directly, the raw
`Array<number, number>` is at this property.

```js
missingBytes.ranges; // [[0, 5]]
```

## Methods

### `NumberRanges.add: (Iterable<number>) => NumberRanges`

- `numbersToAdd: Iterable<number>`
  Numbers to add to this NumberRanges object
- Returns: `NumberRanges`

Adds the passed numbers to the NumberRanges set.

```js
missingBytes.add([0, 6, 10]); // 0-6,10
```

---

### `NumberRanges.remove: (Iterable<number>) => NumberRanges`

Removes the passed numbers from the NumberRanges set.

- `numbersToRemove: Iterable<number>`
  Numbers to remove from this NumberRanges object
- Returns: `NumberRanges`

```js
missingBytes.remove([0, 6, 10]); // 0-5
```

---

### `NumberRanges.union: (NumberRanges) => NumberRanges`

Set union

- `newRanges: NumberRanges`
  `NumberRanges` to unite with this `NumberRanges` object
- Returns: `NumberRanges`

```js
new NumberRanges([0, 2, 4]).union(new NumberRanges({ start: 0, end: 10 })); // 0-10
```

---

### `NumberRanges.difference: (NumberRanges) => NumberRanges`

Set difference

- `newRanges: NumberRanges`
  `NumberRanges` to subtract from this `NumberRanges` object
- Returns: `NumberRanges`

```js
new NumberRanges([0, 1, 2, 5, 6, 7]).difference(new NumberRanges([0, 1, 5])); // 2,6-7
```

---

### `NumberRanges.contains: (number) => boolean`

Search for existance of number in `NumberRanges`.

- `needle: number`
  Number to search for in range.
- Returns: `boolean`

```js
new NumberRanges([0,3,5]).contains(3); // true
```

---

### `NumberRanges.size: () => number`

Returns the number of elements in the NumberRanges

- Returns: `number`

```js
new NumberRanges({ start: 0, end: 99 }).size(); // 100
```

---

### `NumberRanges.min: () => number | null`

Returns the smallest number in the range or `null` if the range is empty.

- Returns: `number | null`

```js
new NumberRanges([10, 32, 238, 1, 43]).min(); // 1
new NumberRanges([]).min(); // null
```

---

### `NumberRanges.max: () => number | null`

Returns the largest number in the range or `null` if the range is empty.

- Returns: `number | null`

```js
new NumberRanges([0, 3, 2, 8, 10, 99, 1]).max(); // 99
new NumberRanges([]).max(); // null
```

---

### `NumberRanges.toString: () => string`
### `NumberRanges.toJSON: () => string`

By default, returns a string like `0-0,10-20,500-600,723-723`, but can be replaced by
passing a custom serializer function when constructed.

The custom serializer will be passed an `Array<number, number>` where the
`number`s represent the start and end of each contiguous range. Note that these
numbers might be the same for ranges that are a single number.

- Returns: `string`

```js
new NumberRanges([0, 2, 3]).toString(); // '0-0,2-3'
new NumberRanges(
    [-1, 0, 2, 3, 5],
    {
        serializer: (ranges) => ranges
            .map(range => `${range[0]}:${range[1]}`)
            .join('###')
    }
).toString(); // '-1:0###2:3##5:5'
```

---

### `NumberRanges.toArray: () => Array<number>`

Convert to an Array containing all numbers in the range. The ranges sorted
internally, so `NumberRanges` is *not* isomorphic to the origin `Iterable`, but
will contain all elements.

- Returns: `Array<number>`

```js
new NumberRanges([3, 2, 1]).toArray(); // [1, 2, 3]
new NumberRanges({ start: 2, end: 10 }).toArray(); // [2, 3, 4, 5, 6, 7, 8, 9, 10]
```

---

### `NumberRanges.findContaining: (needles: Array<number>) => NumberRanges | null`

Return a new `NumberRanges` object that is the matching range that contains all of
the `needles` numbers.

- `needles: Array<number>`
  Numbers to match the range
- Returns: new `NumberRanges`

```js
const ranges = new NumberRanges([0, 1, 2, 3, 5, 6]);
ranges.findContaining([0]); // 0-3
ranges.findContaining([0, 2]); // 0-3
ranges.findContaining([0, 5]); // null
ranges.findContaining([4, 9]); // null
```

---