ReduceRight而不反转阵列

时间:2018-03-30 22:35:34

标签: javascript arrays ecmascript-6

我写过减少JavaScript的原生实现。但是我想看看我们是否可以使用此减少来实现ReduceRight。

Array.prototype.myReduce = function(cb, initialVal) {
  if (!cb)
    throw new Error("No CB defined");

  let [accumulator, ...arr] = initialVal === undefined ? [...this] : [initialVal, ...this];

  for (var i = 0; i < this.length; i++) {
    accumulator = cb.call(undefined, accumulator, arr[i], i, arr);
  }

  return accumulator;
}

我从this article读到了

  

现在你可能会注意到一些事情。不是地图只是一个特例   降低?是!事实上,我们可以用reduce的堂兄来实现地图   reduceRight。 reduceRight就像reduce一样,除了它减少了   反向列出项目。所以,它会首先遇到Nil,   然后是倒数第二个项目,并继续前进,直到它到达第一个   列表中的项目。 reduceRight可以按如下方式实现:

我无法理解如何实施reduceRight(没有反转数组)

这是我的实施:

Array.prototype.myReduceRight2 = function(cb, initialVal) {
  if (!cb)
    throw new Error("No CB defined");

  const arr = [...this].reverse(); //DONOT REVERSE! Looking for alternate solution(s)

  const res = arr.myReduce((acc, val) => {
    return acc.concat(val);
  }, initialVal); // pass initialVal

  return res;
}

3 个答案:

答案 0 :(得分:3)

以下是我在个人图书馆中使用的reduceRight的实现。

<强>代码:

Array.prototype.myReduceRight = function(callback, initialValue) {
  var
    /* Cache the length of the context. */
    length = this.length >>> 0,

    /* Create a counter defaulting at the index of the last element in the context. */
    counter = length - 1;

  /* Check whether a second argument has been given or not. */
  if (arguments.length < 2) {
    /* Repeat until the counter is less than or equal to the length of the
       context or when the counter exists as an index in the context. */
    while (counter >= 0 && !(counter in this)) {
      /* Decrement the counter. */
      counter--;
    }

    /* Set the inital value. */
    initialValue = this[counter--];
  }

  /* Repeat until the counter is less than 0. */
  while (counter >= 0) {
    /* Check whether the counter exists as an index in the context. */
    if (counter in this) {
      /* Set the initial value to be the return value of the given callback. */
      initialValue = callback.call(this, initialValue, this[counter], counter, this);
    }

    /* Decrement the counter. */
    counter--;
  }

  /* Return the calculated value. */
  return initialValue;
}

const array = [1, 2, 3, 4];
console.log(array.myReduceRight((acc, cur) => acc + cur));

答案 1 :(得分:2)

在函数式编程中,reduce又名foldl会像这样减少

foldl (fn, [head:tail], acc) = foldl (fn, tail, fn(acc, head))

foldr就是这个

foldr (fn, [head:tail], acc) = fn (head, foldr(fn, tail, acc))

而JS reduceRight的论点被颠倒了:

reduceRight (fn, [head:tail], acc) = fn (reduceRight(fn, tail, acc), head)

javascript中的所有三个:

&#13;
&#13;
let nil = x => x === nil;

let reduce      = (fn, [h=nil, ...t], a) => nil(h) ? a : reduce(fn, t, fn(a, h));
let foldr       = (fn, [h=nil, ...t], a) => nil(h) ? a : fn(h, foldr(fn, t, a));
let reduceRight = (fn, [h=nil, ...t], a) => nil(h) ? a : fn(reduceRight(fn, t, a), h);

////

xs = [1,2,3,4]
list = (a, b) => `(${a} + ${b})`;

console.log(reduce(list, xs, ''));
console.log(foldr(list, xs, ''));
console.log(reduceRight(list, xs, ''));
&#13;
&#13;
&#13;

要根据map来表达foldr,您需要这样的内容:

let cons = (h, t) => [h, ...t];
let map = (fn, xs) => foldr((x, a) => cons(fn(x), a), xs, []);

答案 2 :(得分:0)

Here是一个reduceRight polyfill:

它使用的循环会减少而不是像解决方案中那样增量。

// Production steps of ECMA-262, Edition 5, 15.4.4.22
// Reference: http://es5.github.io/#x15.4.4.22
if ('function' !== typeof Array.prototype.reduceRight) {
  Array.prototype.reduceRight = function(callback /*, initialValue*/) {
    'use strict';
    if (null === this || 'undefined' === typeof this) {
      throw new TypeError('Array.prototype.reduce called on null or undefined');
    }
    if ('function' !== typeof callback) {
      throw new TypeError(callback + ' is not a function');
    }
    var t = Object(this), len = t.length >>> 0, k = len - 1, value;
    if (arguments.length >= 2) {
      value = arguments[1];
    } else {
      while (k >= 0 && !(k in t)) {
        k--;
      }
      if (k < 0) {
        throw new TypeError('Reduce of empty array with no initial value');
      }
      value = t[k--];
    }
    for (; k >= 0; k--) {
      if (k in t) {
        value = callback(value, t[k], k, t);
      }
    }
    return value;
  };
}