2015-11-13 30 views
2

我对js很新,试图用reduce替换for循环,并遇到麻烦。试图了解减少使用一个对象作为previousValue

据我所知,||只评估左操作数。如果是真的,它会作为价值传递。如果它是虚假的,那么正确的操作数会被传递而不被评估,因为它是决定性的因素。

由于某些原因,这个工作在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) 
) 
+2

'reduce'回调应该'return'。无论返回什么,都将作为第一个参数在下一次迭代中传递。 – zerkms

+0

@zerkms哦对。咄。这很尴尬。谢谢。 –

+0

不要评论你问的部分问题。格式化的SO代码变暗,使其难以阅读。 – Barmar

回答

2

reduce,你为以前的值是无论你在过去的迭代中返回。所以:

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

的正确的使用方法减少在这里,将属性添加到对象并返回它

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 } 
}, {}); 

注意,后一个版本(或Object.assign如果你ES2015有限)将创建的每个新对象转。对于成千上万可能成为问题的对象。

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