使用JavaScript Reduce生成对象

时间:2018-12-03 02:38:16

标签: javascript arrays functional-programming reduce

我有一个数字数组[22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123],我需要使用reduce来创建一个看起来像这样的对象:

{  
   numbersLessThanTen: [...],  
   numbersGreaterThanTen: [...]
}

我有解决方法,如下:

const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];


const groupedBySize = listOfNumbers.reduce((total, next) => {
  const less = total.numbersLessThanTen || [];
  const more = total.numbersGreaterThanTen || [];
  
  next > 10 ? total.numbersGreaterThanTen = [].concat(more, next) : total.numbersLessThanTen = [].concat(less, next);
  return total;
  
}, {});

我的问题是,为什么以下各项不起作用?它只是返回初始值。当我使用.push()而不是.concat()时,它可以工作,但我真的很想了解为什么这种方式不起作用。谢谢!

const groupedBySize = listOfNumbers.reduce((total, next) => {
  // const less = total.numbersLessThanTen || [];
  // const more = total.numbersGreaterThanTen || [];
  
  next > 10 ? total.numbersGreaterThanTen.concat(next) : total.numbersLessThanTen.concat(next);
  return total;

}, {numbersGreaterThanTen: [], numbersLessThanTen:[]});

4 个答案:

答案 0 :(得分:1)

代码let result = vm.comparisonThumbnail.list.map(v => v.courseContentId).sort(); 无效的原因是let result = vm.comparisonThumbnail.list .map(v => Number(v.courseContentId)) .filter(v => !isNaN(v)) .sort(); 将合并的结果作为新数组返回。当您的reduce函数运行时,合并工作已完成,但是该合并的结果未分配给任何对象(即concat()中的字段)。这就是输出结果与输入相同的原因-total中的数组从未真正更新过。 following is from MDN

  

concat方法创建一个新数组,该数组由调用该对象的对象中的元素组成。

另一方面,total方法实际上是更改/更新了被调用的数组,将直接传递给该数组实例的数据添加了。这意味着每次迭代调用push()时,push()中的数组将直接更新,这就是这种方法起作用的原因:

  

push方法将值附加到数组。

答案 1 :(得分:1)

其他人解释了为什么这种方法不起作用,并给出了合理的答案,继续进行突变。

这是一种不会变异任何数据的方法:

const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];

const groupedBySize = nbr => nbr.reduce 
  ( ({ gt10, lte10 }, next) => next > 10 
     ? { gt10: gt10 .concat(next), lte10 } 
     : { gt10, lte10: lte10 .concat(next) }
  , { gt10: [], lte10: [] }
  )

console.log(groupedBySize(listOfNumbers))

我也缩写了属性名称。显然,您可以延长它们的长度。但是请注意,"numbersLessThanTen"有点误导,因为其中包括10

答案 2 :(得分:1)

您可以确定三元组,然后是push()而不是concat()

let n = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123]

let obj = n.reduce((obj, n) => {
    (n < 10 
     ? obj.numbersLessThanTen
     : obj.numbersGreaterThanTen
    ).push(n)
    return obj
}, {numbersLessThanTen: [],  numbersGreaterThanTen:[]})

console.log(obj)

答案 3 :(得分:0)

Array.concat不会变异对其进行调用的数组。您假设这样做,而不是根据docs将结果分配给任何内容:

  

此方法不会更改现有数组,而是返回一个   新数组

因此,要获得所需的代码,可以执行以下操作:

const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];

const groupedBySize = listOfNumbers.reduce((total, next) => {  
  let key = next > 10 ? 'numbersGreaterThanTen' : 'numbersLessThanTen'
  total[key] = total[key].concat([next]); // <-- assign the result
  return total;
}, {numbersGreaterThanTen: [], numbersLessThanTen: []});

console.log(groupedBySize)

或者,您可以执行以下操作:

const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];

const groupedBySize = listOfNumbers.reduce((ttl, nxt) => 
 (ttl[nxt > 10 ? 'numbersGreaterThanTen' : 'numbersLessThanTen'].push(nxt), ttl), 
 {numbersGreaterThanTen: [], numbersLessThanTen:[]});

console.log(groupedBySize)

做同样的事情,但是使用Array.push,该mutates通过插入项目来select r.role_id, stuff( (select ',' + convert(varchar(max), permission_id) from user_role_permission urp where urp.role_id = r.role_id for xml path ('') ), 1, 1, '' ) as permissions from (select distinct role_id from user_role_permission) r; 在其上调用的数组。