尝试理解使用对象作为previousValue减少

时间:2015-11-13 22:19:25

标签: javascript

我对js很新,尝试用reduce替换for循环并遇到麻烦。

据我了解,||仅评估左操作数。如果它真实,它就作为价值传递。如果它是假的,那么右操作数在没有被评估的情况下被传递,因为它是决定因素。

出于某种原因,这适用于for循环,但不适用于reduce。难道不能在第一次迭代时阅读obj[val]obj[arr[ind]]使其返回0 + 1吗?

'use strict';

let strings = ["One", "Two", "Two", "Three", "Three", "Three"];

let findMostCommon = (arr) => {
    let str;
    let obj;
    let keys;
    let counter;

    str = "";
    obj = {};
    counter = 0;

    for (let i = 0; i < arr.length; i++){
        console.log(arr[i]); // One, Two, Two, Three, etc.
        obj[arr[i]] = (obj[arr[i]] || 0) + 1; // Works
    }

/*
    arr.reduce((obj, val, ind, arr) => {
        obj[val] = (obj[val] || 0) + 1;
    }, obj) 

    obj[val] = (obj[val] || 0) + 1;
                   ^
    TypeError: Cannot read property 'Two' of undefined
*/

/* 
    arr.reduce((obj, val, ind, arr) => {
        obj[arr[ind]] = (obj[arr[ind]] || 0) + 1;
    }, obj)

    obj[arr[ind]] = (obj[arr[ind]] || 0) + 1;
                        ^
    TypeError: Cannot read property 'Two' of undefined
*/

    keys = Object.keys(obj);

    for (let i in obj){
        if (obj[i] > counter){
            counter = obj[i]
        }
    }

    str = keys[counter - 1];

    return str;
}

console.log(
    findMostCommon(strings)
)

1 个答案:

答案 0 :(得分:2)

reduce中,您之前获得的值是您在上一次迭代中返回的值。所以:

[1,2,3,4,5,6].reduce(function(sumSoFar, currentNumber){
    return sumSoFar + currentNumber; // whatever I return here is the next value
}, 0);

在这里使用reduce的正确方法是将属性添加到对象并将其返回

arr.reduce((obj, val, ind, arr) => {
    obj[arr[ind]] = (obj[arr[ind]] || 0) + 1; // arr[ind] is just val btw
    return obj; // LOOK AT ME
}, obj);

当然,使用较新的ES功能可以获得更好的效果:

arr.reduce((obj, val) => {
    return {...obj, [val] : (obj[val] || 0) + 1 }
}, {});

请注意,后一版本(或者如果您受ES2015限制,使用Object.assign)将在每个回合中创建一个新对象。对于可能存在问题的数千个对象。

使用lodash,顺便说一下,这只是_.countBy(arr):)