用对象作为累加器的数组归约

时间:2018-12-02 15:11:23

标签: javascript

let str = "baaabbabbsbsssssabbaaaa";

与此

[...str].reduce((characterMap, char) => {
    if (!characterMap[char]) characterMap[char] = 1;
    else characterMap[char]++;
    return characterMap;
}, {})

我得到{b:8,a:9,s:6}

但是当我把它简化为这个

[...str].reduce((characterMap, char) => !characterMap[char] ? characterMap[char] = 1 : characterMap[char]++, {});

它打印出1而不是{b:8,a:9,s:6}

为什么?

我首先使用减少错误吗?

3 个答案:

答案 0 :(得分:4)

  

我该如何缩短?

通过:

  1. 不尝试将其刺入reduce。 :-) reduce在累加器值更改时适当使用。就您而言,事实并非如此。

  2. 不使用数组包装器。字符串是可迭代的,因此请直接使用该事实。

  3. 使用curiously-powerful || operator¹默认字符计数(如果不存在)。

只需使用循环:

const characterMap = {};
for (const char of str) {
    characterMap[char] = (characterMap[char] || 0) + 1;
}

实时示例:

let str = "baaabbabbsbsssssabbaaaa";
const characterMap = {};
for (const char of str) {
    characterMap[char] = (characterMap[char] || 0) + 1;
}
console.log(characterMap);

但是如果您确实要使用reduce,则可以应用||技巧并使用较短的名称:

const characterMap = [...str].reduce((acc, ch) => {
    acc[ch] = (acc[ch] || 0) + 1;
    return acc;
}, {});

实时示例:

let str = "baaabbabbsbsssssabbaaaa";
const characterMap = [...str].reduce((acc, ch) => {
    acc[ch] = (acc[ch] || 0) + 1;
    return acc;
}, {});
console.log(characterMap);

您可以(ab)使用逗号运算符将其强制转换为简洁的箭头功能,但会牺牲可读性和可维护性(IMHO)。

  

但是当我把它简化为这个

[...str].reduce((characterMap, char) => !characterMap[char] ? characterMap[char] = 1 : characterMap[char]++, {});
     

它打印出1而不是{b:8,a:9,s:6}

     

为什么?

因为您的回调函数返回!characterMap[char] ? characterMap[char] = 1 : characterMap[char]++而不是对象的结果。因此,对它的后续调用将获得该数字,而不是对象,并且characterMap[char]始终为false(因为1["a"]undefined,等等。)


¹(在我贫乏的小博客上)

答案 1 :(得分:1)

您需要将返回的累加器作为结果。

var str = "baaabbabbsbsssssabbaaaa",
    result = [...str].reduce((characterMap, char) => {
        characterMap[char] = (characterMap[char] || 0) + 1; // take default value of zero
        return characterMap;
    }, {});

console.log(result)

  

但是当我把它简化为这个

[...str].reduce((characterMap, char) => !characterMap[char] ? characterMap[char] = 1 : characterMap[char]++, {});
     

它打印出1而不是{ b: 8, a: 9, s: 6 }

     

为什么?

仅仅是因为在第一个循环中

!characterMap[char] ? characterMap[char] = 1 : characterMap[char]++

这条路线

!characterMap[char] ? characterMap[char] = 1 : characterMap[char]++
^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^
true                  characterMap['b'] = 1

返回1

,并在随后的所有迭代中,采用数字1并尝试获取该数字的属性a(或字符串的所有后续字母),即undefined < / p>

!characterMap[char] ? characterMap[char] = 1 : characterMap[char]++
^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^
!1['a']
true                  1['b'] = 1

结果为1

答案 2 :(得分:0)

如果要坚持使用箭头表达式语法,可以使用comma operator

[...str].reduce((characterMap, chr) => 
    (characterMap[chr] = (characterMap[chr] || 0) + 1, characterMap), {});

或者您可以使用Object.assign

[...str].reduce((characterMap, chr) => 
    Object.assign(characterMap, {[chr]: (characterMap[chr] || 0) + 1}), {});