reverse-iterable-map
The ReverseIterableMap
object is a reverse-iterable map implementation based on the built-in Map object.
Links:
See also:
Table of Contents
Install
ES Module
Download only the ES module file:
curl -O https://raw.githubusercontent.com/kleinfreund/reverse-iterable-map/master/src/reverse-iterable-map.mjs
Node.js package
(Requires Node version 8.5 or higher for ES module support)
Installs the node package as a dependency. It doesn’t have any dependencies itself.
npm install --save reverse-iterable-map
Note, that Node.js version 8.5 or higher is required, as it comes with experimental support for ES modules. If you don’t want to use it as an ES module, you will need to transpile the package yourself.
Usage
import { ReverseIterableMap } from './src/reverse-iterable-map.mjs';
const map = new ReverseIterableMap();
For more usage examples, have a look at kleinfreund.github.io/reverse-iterable-map.
You can also run the examples locally after cloning the repository:
npm install && npm run examples
Tests
… with Node’s experimental ES module feature:
npm test
Documentation
Disclaimer: The documentation section copies a lot of content from the Map
documentation on the Mozilla Developer Network.
A ReverseIterableMap
object iterates its elements in insertion or reverse-insertion order — a for...of
loop returns an array of [key, value]
for each iteration.
Constructor
Syntax
new ReverseIterableMap([iterable])
Parameters:
-
iterable
: An iterable object whose elements are key-value pairs.
In order to construct a ReverseIterableMap
object from an array, it can be passed by calling the Array.prototype.entries()
method.
const map = new ReverseIterableMap([1, 2, 3].entries());
Usage
const map = new ReverseIterableMap();
Array
const map = new ReverseIterableMap([1, 2, 3].entries());
Array
of Array
s
const map = new ReverseIterableMap([[0, 1], [1, 2], [2, 3]]);
Map
const builtInMap = new Map([['key1', 1], ['key2', 2], ['key3', 3]]);
const map = new ReverseIterableMap(builtInMap);
NodeList
const nodeList = document.querySelectorAll('a');
const map = new ReverseIterableMap(nodeList.entries());
clear()
Syntax
map.clear();
Return value:
undefined
.
Usage
map.clear();
has()
Syntax
map.has(key);
Parameters:
- key: Required. The key of the element to test for presence in the
ReverseIterableMap
object.
Return value:
- Boolean: Returns
true
if an element with the specified key exists in the ReverseIterableMap
object; otherwise false
.
Usage
const map = new ReverseIterableMap(['hey', 'beauty'].entries());
map.has(0);
map.has(1);
map.has(2);
get()
Syntax
map.get(key);
Parameters:
- key: Required. The key of the element to return from the
ReverseIterableMap
object.
Return value:
- Returns the element associated with the specified key or
undefined
if the key can't be found in the ReverseIterableMap
object.
Usage
const map = new ReverseIterableMap(['hey', 'beauty'].entries());
map.get(0);
map.get(1);
map.get(2);
set()
Syntax
map.set(key, value);
Parameters:
- key: Required. The key of the element to add to the
ReverseIterableMap
object. - value: Required. The value of the element to add to the
ReverseIterableMap
object.
Return value:
- The
ReverseIterableMap
object.
Usage
const map = new ReverseIterableMap();
map.set('you', 'beauty');
map.set('the-magic-key', 'hey');
The set()
method returns a reference to the map object. This makes the set operation chainable.
const map = new ReverseIterableMap()
.set('key', '… is spelled like tea')
.set('hey', '… somehow ney');
setFirst()
The setFirst()
method functions like set()
but uses reverse-insertion order.
Syntax
map.set(key, value);
Parameters:
- key: Required. The key of the element to add to the
ReverseIterableMap
object. - value: Required. The value of the element to add to the
ReverseIterableMap
object.
Return value:
- The
ReverseIterableMap
object.
Usage
const map = new ReverseIterableMap()
.setFirst('key1', 'was inserted first')
.setFirst('key2', 'was inserted last');
map.getFirst();
map.getLast();
delete()
Syntax
map.delete(key);
Parameters:
- key: Required. The key of the element to remove from the
ReverseIterableMap
object.
Return value:
- Boolean: Returns
true
if an element in the ReverseIterableMap
object existed and has been removed, or false
if the element does not exist.
Usage
const map = new ReverseIterableMap(['hey', 'beauty'].entries());
map.delete(0);
map.delete(1);
map.delete(2);
forEach()
The forEach()
method executes a provided function once per each [key, value]
pair in the ReverseIterableMap
object, in insertion order.
Syntax
map.forEach(callback[, thisArg]);
Parameters:
- callback: Function to execute for each element.
- thisArg: Value to use as
this
when executing callback
.
Return value:
undefined
.
forEachReverse()
The forEachReverse()
method executes a provided function once per each [key, value]
pair in the ReverseIterableMap
object, in reverse-insertion order.
Syntax
map.forEachReverse(callback[, thisArg]);
Parameters:
- callback: Function to execute for each element.
- thisArg: Value to use as
this
when executing callback
.
Return value:
undefined
.
[Symbol.iterator]()
Returns the map iterator function. By default, this is the entries()
function.
Syntax
map[Symbol.iterator]();
Return value:
The map iterator function, which is the entries()
function by default.
Usage
const map = new ReverseIterableMap([1, 2, 4].entries());
const iterator = map[Symbol.iterator]();
iterator.next().value;
iterator.next().value;
iterator.next().value;
iterator.next().value;
reverse()
In theory, following the semantics of [Symbol.iterator]()
, this should be [Symbol.reverseIterator]()
. However, as a developer, I cannot define a well-known symbol myself and make use of it. In the future, the a proposal like The ReverseIterable Interface, by Lee Byron might make it’s way into the specification. For the time being, the reverse()
function serves the same purpose.
Syntax
map.reverse();
Return value:
The map reverse-iterator function, which is the entries().reverse()
function by default.
Usage
const map = new ReverseIterableMap([1, 2, 4].entries());
const reverseIterator = map.reverse();
reverseIterator.next().value;
reverseIterator.next().value;
reverseIterator.next().value;
reverseIterator.next().value;
entries()
Returns an iterator containing the [key, value]
pairs for each element in the ReverseIterableMap
object in insertion order.
An iterator containing the same pairs in reverse-insertion order can be obtained with entries().reverse()
.
Syntax
map.entries();
Return value:
A new ReverseIterableMap
iterator object.
keys()
Returns an iterator containing the keys for each element in the ReverseIterableMap
object in insertion order.
An iterator containing the same keys in reverse-insertion order can be obtained with keys().reverse()
.
Syntax
map.keys();
Return value:
A new ReverseIterableMap
iterator object.
values()
Returns an iterator containing the values for each element in the ReverseIterableMap
object in insertion order.
An iterator containing the same values in reverse-insertion order can be obtained with values().reverse()
.
Syntax
map.values();
Return value:
A new ReverseIterableMap
iterator object.
iteratorFor()
Returns an iterator containing the [key, value]
pairs for each element in the ReverseIterableMap
object in insertion order starting with the pair specified by the key
parameter.
This allows starting iteration at a specific element in the map.
An iterator containing the same pairs in reverse-insertion order can be obtained with iteratorFor().reverse()
.
Syntax
map.iteratorFor(key);
Parameters:
- key: Required. The key of the element to start iterating from.
Return value:
A new ReverseIterableMap
iterator object.
Usage
const map = new ReverseIterableMap([1, 2, 4].entries());
const iterator = map.iteratorFor(1);
iterator.next().value;
iterator.next().value;
iterator.next().value;
const reverseIterator = map.iteratorFor(1).reverse();
reverseIterator.next().value;
reverseIterator.next().value;
reverseIterator.next().value;
Why this was implemented
Part of the additions to ECMAScript 2015 are the iteration protocols: Iterable and iterator. The former allows arbitrary objects to become iterable. Following the rules of the protocol gives one iteration capabilities via the following techniques:
However, only the iteration in one direction is considered by the specification at the time. This means that we only get forward-iteration by default. There is a draft for a proposal to add a ReverseIterable
interface to the specification: “The ReverseIterable Interface” by Lee Byron.
Now, with the iteration protocols, we could redefine the iteration behavior for our purpose and make an object backwards-iterable. At the same time, this means losing the ability to iterate forwards.
If you need both a forwards- and backwards-iterable object, this implementation might be for you.
But why a map?
That’s what I needed. To be precise, I needed to access an iterator at a specific location in my data structure and be able to iterate in both directions.
I tried to stick to the Map
interface as close as possible.
Implementing a reverse-iterable array, for example, can be accomplished by using the same techniques of this implementation.
How to update this package
… because I keep forgetting that.
Let’s assume an update to version v3.1.0
should be made. First of all, the working directory needs to cleaned up; all changes need to be comitted and pushed.
git add .
git commit -m "Implemented extremely nice feature"
git push
Next, make sure you have a valid NPM authentication token set up:
npm whoami
If not, do that with npm login
and continue. We now create a new commit with the version tag (i.e. v3.1.0
) and update the package.json. Actually, the following command will do that:
npm version v3.1.0
This creates a new git tag that we need to publish as well. With that, we can now publish the new version.
git push origin v3.1.0
npm publish
That’s it.