14

In ES6 we now have iterators and for..of to iterate them. we have some built-ins for arrays; notably keys, values and entries.

These methods allow one to perform much of the iteration one would commonly perform. But, what about iteration in reverse? This is also a very common task and I don't see anything in the spec specifically for it? Or maybe I missed it?

Ok, we have Array.prototype.reverse but I don't necessarily want to reverse a large array in place and then reverse it again when finished. I also don't want to use Array.prototype.slice to make a temporary shallow copy and reverse that just for iteration.

So I took a look a generators and came up with these working solutions.

(function() {
  'use strict';

  function* reverseKeys(arr) {
    let key = arr.length - 1;

    while (key >= 0) {
      yield key;
      key -= 1;
    }
  }

  function* reverseValues(arr) {
    for (let key of reverseKeys(arr)) {
      yield arr[key];
    }
  }

  function* reverseEntries(arr) {
    for (let key of reverseKeys(arr)) {
      yield [key, arr[key]];
    }
  }

  var pre = document.getElementById('out');

  function log(result) {
    pre.appendChild(document.createTextNode(result + '\n'));
  }

  var a = ['a', 'b', 'c'];

  for (var x of reverseKeys(a)) {
    log(x);
  }

  log('');
  for (var x of reverseValues(a)) {
    log(x);
  }

  log('');
  for (var x of reverseEntries(a)) {
    log(x);
  }
}());
<pre id="out"></pre>

Is this really the way that reverse iteration is intended in ES6 or have I missed something fundamental in the spec?

Xotic750
  • 22,914
  • 8
  • 57
  • 79
  • No, the spec really has nothing like this. But as you see, it's quite trivial to write using generators. – Bergi Sep 07 '15 at 19:17
  • 1
    I think there was some discussion on the mailing list regarding reversible iterators. Edit: Ah, here it is: https://esdiscuss.org/topic/reverseiterable-interface – Bergi Sep 07 '15 at 19:17
  • @Bergi Thanks, not much discussion but a proposal and then quiet, and now definitely not in the spec. The main things that appear missing are reverse iteration of arrays and with strings; keys and entries (values is there but not name, must use `Symbol.iterator`) plus reverse methods. Yes, the array generators were trivial but the strings ones a little more complex, still not something that I want to write and re-write again and again. I will post an answer to my question with some code that I am using to fill the gap. – Xotic750 Sep 08 '15 at 18:50
  • Ah, I see, reverse String iterators [wouldn't be as easy](http://www.ecma-international.org/ecma-262/6.0/#sec-%stringiteratorprototype%.next)… – Bergi Sep 08 '15 at 19:04
  • There is a reduceRight method if that serves your use case. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight – FluffyBeing Mar 23 '21 at 01:56

2 Answers2

8

Is this really the way that reverse iteration is intended in ES6?

There was a proposal for reverse iteration, discussed on esdicuss and a git project outlining a spec, but nothing much seemed to happen with respect to it. ES6 is finalised now, so it's not something that is going to be added this time around. Anyway, for arrays and strings I've written a little code to fill in the gaps (in my opinion) and I will post it here as it may help others. This code is based on my browsers today and some improvements could possibly be made if there was more of ES6 implemented on them. I may get around to a gist or a small github project later.

Update: I have created a GitHub project for work on this.

Xotic750
  • 22,914
  • 8
  • 57
  • 79
3

Have a look at https://www.npmjs.com/package/itiriri.
It's a library that has similar methods as arrays, but works with iterators.

import { query } from 'itiriri';

const m = new Map();
m.set(1, 'a');
m.set(2, 'b');
m.set(3, 'c');

const result = query(m);

for (const [k, v] of result.reverse()) {
  console.log(k + ' - ' + v)
}

query returns an iterable that has similar methods as arrays. In above example reverse() is used. There are also fitler, slice, map, concat etc.

If you need back an array, or a map from a query you can use one of .toArray(), .toMap() or .toSet() methods.