Skip to content

Latest commit

 

History

History
108 lines (77 loc) · 5.24 KB

.README.md

File metadata and controls

108 lines (77 loc) · 5.24 KB

Iterable range

npm version Open Source Love ISC License build status code coverage documentation dependency version status dev dependency version status Code Climate

Quickstart

npm i iter-range
const range = require("iter-range");

for (let i of range(10, 0, -1)) {
  console.log(i);
}
console.log("Midnight!");

range(4).forEach(() => console.log("#winning"));

Introduction

This is just a sweet little range library. It implements the same basic API as the python range function: range([start = 0], stop, [step = 1]). The key differentiator between this library and the other JavaScript range libraries that I have seen is that it does not create and populate arrays with the given parameters. Instead, I provide you a factory function that builds iterable Range objects.

Range objects also include lazily-evaluated implementations of many Array.prototype methods that match their Array counterparts nearly exactly. If you really want an array, you can always use Array.from(range(2, 12)) or the spread operator [...range(5)]. There is also a get method, which will return the value at a given index.

Note that (with the exception of map, reduce, reduceRight, and filter), these are all constant-space methods. They take advantage of the object's iterable nature and don't create any additional arrays or objects. Furthermore, those that accept a callback are written to break early if possible; a some call that matches on the first item stops there and returns. Likewise, indexOf, lastIndexOf, includes, and get are all constant-time operations.

Range

This library exports a single function range, which is a factory for producing Range objects. Range objects are iterable and have a length:

const range = require("iter-range");

for (let i of range(5)) {
  console.log(i); // logs 0, then 1, then 2, etc.
}

// Decreasing and non-integer parameters work a treat:
console.log(...range(27, 8, -4.5)); //=> 27 22.5 18 13.5 9

// The iterator resets when consumed:
const r = range(3);
console.log(...r); //=> 0 1 2
console.log(Array.from(r)); //=> [0, 1, 2]
console.log(...r); //=> 0 1 2

// They have a length property
console.log(range(5).length); //=> 5
console.log(range(0, 10, 3).length); //=> 4

Additionally, Range objects have a whole posse of the standard Array.prototype methods (and get):

const range = require("iter-range");
console.log(range(3, 6).map((i, index) => [i, index])); //=> [[3, 0], [4, 1], [5, 2]]
console.log(...range(5).reverse()); //=> 4 3 2 1 0
console.log(range(8).filter(i => i % 2 === 0)); //=> [0, 2, 4, 6]
console.log(range(2.5, -2.75, -0.25).includes(1)); //=> true
console.log(range(10, 0, -1).indexOf(3)); //=> 7
console.log(range(2.5, 15, 1.25).get(2)); //=> 5

I have strived to match the Array API precisely for these methods. For details, refer to the Range API documentation below.

Exceptions

  • Since these methods don't construct an array to iterate over, there is no array to pass to the callbacks that would normally receive them. Instead they pass the Range object as the third parameter. I hope that's helpful.

  • Reverse does not mutate the Range it is called on, it just returns a new instance.

Development

The Range object methods are thoroughly tested to match their Array.prototype counterparts (except as noted). Please let me know if I've missed or wrongly implemented anything. Jasmine is used for tests, Istanbul is used to ensure complete test coverage, ESLint is used for linting, and jsdoc-to-markdown is used to generate the documentation. You can prepare the dev environment by cloning the repository and installing the dependencies ($ npm i).

  • Tests: npm test
  • Coverage: npm coverage
  • Linting: npm run lint
  • Documentation: npm run doc

API

{{#function name="range"}} {{>docs}} {{/function}}

{{#class name="Range"}} {{>docs}} {{/class}}

{{#identifier name="iterCallback"}} {{>docs}} {{/identifier}}

{{#identifier name="reduceCallback"}} {{>docs}} {{/identifier}}