_.reduce() 的重新实现

如何解决_.reduce() 的重新实现

下面的代码是 _.reduce() 方法的重新实现。它不是我的,但我用它来了解 _.reduce 是如何工作的。它目前在两项测试中失败:

  1. 应该能够将集合减少到单个值 - AssertionError: expected 'aabcdabcdabcdabcd' to equal 'abcd'
  2. 支持初始状态 AssertionError:预期 'initabcdabcdabcdabcd' 等于 'initabcd'
_.reduce = function (list,iteratee,memo,context) {
  if (context) iteratee = iteratee.bind(context);
  _.each(list,(elem,index) => {
    if (memo === undefined) {
      memo = elem;
      memo =iteratee(memo,elem,index,list);
    } else memo = iteratee(memo,list);
  });
  return memo;
};

我不明白为什么会这样。在我看来,这应该按预期运行。谁能提供进一步的信息?

更新 由于@georg 发现了我的 _.each() 函数的问题,我能够解决第二个错误。第一个错误仍然存​​在,但略有不同:

  1. 应该能够将集合减少到单个值 断言错误:预期“aabcd”等于“abcd”

这是与错误消息相关的测试代码

var mocks = {
  arr: ['a','b','c','d'],// >= 4 elements,all should be truthy
  obj: {a:1,b:2,c:3,d:4},// >= 4 values,all should be truthy
  halfTruthyArr: [null,null,half should be falsy
  halfTruthyObj: {a:1,b:null,d:null},half should be falsy
  string: 'This is a string.',reverseString: function (string) {
    if (typeof string === 'string') return string.split('').reverse().join('');
  }
};

   describe('reduce',function () {

    afterEach(function () {
      called = false;
    });

    it('should be able to reduce a collection to a single value',function () {
      _.reduce(mocks.arr,function (accumulator,el,i,arr) {
        arr[i].should.equal(el);
        return accumulator.toString() + el.toString();
      }).should.equal(mocks.stringifiedArrElms);
    });

解决方法

这是错误的:

  memo = elem[0];
  memo =iteratee(memo,elem,index,list);

应该

  memo = elem

基本上,当没有给出init值时,你应该把第一个元素作为当前值,不要在它上面调用回调。

_ = {}

_.each = (a,fn) => a.forEach(fn)

_.reduce = function (list,iteratee,memo,context) {
    if (context) iteratee = iteratee.bind(context);
    _.each(list,(elem,index) => {
        if (memo === undefined)
            memo = elem;
        else
            memo = iteratee(memo,list);
    });
    return memo;
};


console.log(_.reduce([1],(a,x) => a + '|' + x))
console.log(_.reduce([1,2,3],x) => a + '|' + x))

console.log(_.reduce([1],x) => a + '|' + x,'@'))
console.log(_.reduce([1,'@'))

当然,memo === undefined 非常幼稚(没有什么可以阻止回调在中间的某个地方返回 undefined),一个更安全的选择是

let noMemo = Symbol();
if (arguments.length < 3)
    memo = noMemo;

_.each(list,index) => {
    if (memo === noMemo)
        memo = elem;
    else...
,

georg 已经在他的回答中指出了这一点,但我想我可以说得更明确一点:您使用了第一个元素两次。以下代码片段旨在在未提供初始累加器时使用列表的第一个元素:

    if (memo === undefined) {
      memo = elem;
      memo =iteratee(memo,list);
    }

我们可以将赋值中的 elem 替换为 memo 以查看第一个元素如何最终被使用两次:

    if (memo === undefined) {
      memo =iteratee(elem,list);
    }

解决方案是简单地不在第一个元素上调用 iteratee,正如 georg 已经暗示的那样:

    if (memo === undefined) {
      memo = elem;
    }

georg 还建议使用唯一的 Symbol() 来更可靠地指示第一个元素,而不是 undefined,后者也可能是您的 iteratee 在集合中途的返回值。另一种方法是简单地使用布尔状态变量(下面命名为 first):

_.reduce = function (list,context) {
  var first = false;
  if (arguments.length < 3) {
    first = true;
  } else if (context) {
    iteratee = iteratee.bind(context);
  }
  _.each(list,index) => {
    if (first) {
      memo = elem;
      first = false;
    } else memo = iteratee(memo,list);
  });
  return memo;
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?