简体   繁体   English

使用Reduce将数组转换为对象

[英]Converting Array to Object using Reduce

Can someone explain how this is working. 有人可以解释这是如何工作的。

Learning to use Array.reduce() 学习使用Array.reduce()

var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza'];

var initialValue = {}

var reducer = function(tally, vote) {
  if (!tally[vote]) {
      tally[vote] = 1;
  } else {
      tally[vote] = tally[vote] + 1;
  }
      return tally;
  }

var result = votes.reduce(reducer, initialValue)

The way how reduce works is pretty similar to map or filter . reduce的工作方式与mapfilter非常相似。 In this case, the reducer is responsible for reducing the array of objects into one object. 在这种情况下,reducer负责对象数组简化为一个对象。

The reducer function iterates through all elements of your array. reducer函数遍历数组的所有元素。 The function is called with two arguments, tally - result of reducing so far and vote - array element that is currently being processed . 该函数使用两个参数调用, tally 到目前为止减少的结果当前正在处理的 vote 数组元素

If tally does not have a property named just like the element that is currently being processed/reduced, it adds such a key to the object and sets its value to one. 如果tally没有像当前正在处理/缩减的元素那样命名的属性,则它将这样的键添加到对象并将其值设置为1。 Otherwise (key is present), it's incremented by one. 否则(存在密钥),它将增加一。

For more information go here 欲了解更多信息,请点击这里

Basically Array.prototype.reduce() method applies a function against an accumulator and each value of the array to reduce it to a single value. 基本上, Array.prototype.reduce()方法对一个累加器和数组的每个值应用一个函数,以将其减少为单个值。

In your example the reduced value (the result of a count operation) is assigned as a property of an object called tally which is returned by .reduce() ; 在您的示例中,将减小的值(计数操作的结果)分配为称为tally的对象的属性,该对象由.reduce()返回;

I comment your with a brief explanation: 我用简短的解释评论您:

 // your data in an array var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza']; // optional value to use as the first argument to the first call of the callback when using Array.prototype.reduce(). var initialValue = {} // tally = previousValue and vote = currentValue var reducer = function(tally, vote) { // if tally is not assign as a key in tally object, add key and add value of one, (basically count 1 for one element in your votes array) if (!tally[vote]) { tally[vote] = 1; } else { // otherwise if tally object has already this key, increment its value by one, (basically it counts how many times each item in votes array is present in the array) tally[vote] = tally[vote] + 1; } return tally; } var result = votes.reduce(reducer, initialValue); console.log(result); 

Notes: you can actually avoid using of declaring a variable for initialValue and instead using only var result = votes.reduce(reducer, {}); 注意:实际上,您可以避免使用为initialValue声明变量,而只使用var result = votes.reduce(reducer, {});

API documentation: API文档:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Some more examples and brief explanation: 更多示例和简要说明:

https://www.airpair.com/javascript/javascript-array-reduce https://www.airpair.com/javascript/javascript-array-reduce

I inserted some console.log messages in your code and this helped me understand what was going on. 我在您的代码中插入了一些console.log消息,这有助于我了解发生了什么。

 var votes = ['tacos', 'pizza', 'pizza', 'tacos', 'fries', 'ice cream', 'ice cream', 'pizza']; var initialValue = {} var reducer = function(tally, vote) { console.log("tally: ", tally); console.log("vote: ", vote); console.log("tally[vote]: ", tally[vote]); if (!tally[vote]) { tally[vote] = 1; } else { tally[vote] = tally[vote] + 1; } return tally; } var result = votes.reduce(reducer, initialValue) console.log("result: " + JSON.stringify(result)); 

There's plenty of verbose explanations of reduce here and other places, but I think a simple visual demonstration might help 在这里和其他地方有很多关于reduce的冗长解释,但我认为简单的视觉演示可能会有所帮助

[1,2,3].reduce(function(a,b) { return a + b }, 0)
// (((0 + 1) + 2) + 3)
// => 6

You can see: 您可以看到:

  • an input list of 3 elements results in 3 computations 3个元素的输入列表将导致3次计算
  • the initial value is used in the computation with the first element 初始值用于第一个元素的计算
  • the result of one computation is used in the next computation … 一个计算的结果将在下一个计算中使用…
  • … up until the last computation which is the result of reduce …直到最后的计算,这是reduce的结果

Now as for your code, we're not building a sum of numbers, we're building up an Object that holds the tally count of each string in an array. 现在,对于您的代码,我们并没有建立数字的总和,而是建立了一个Object ,它保存数组中每个字符串的计数计数。

There's no point in me explaining what everyone else did, but it's not surprising this might've been confusing for you because no one explained that this is abuse of an Object. 我没有必要解释其他所有人的所作所为,但这不足为奇,这并不奇怪,因为没有人解释这是对Object的滥用。

In truth, an Object is actually not the best data structure choice for this reduction. 实际上,对于这种简化,对象实际上不是最佳的数据结构选择。 Here, an Object is used to emulate the behaviour of a Map . 在这里,对象用于模拟Map的行为。

We'll set initialValue to a new Map() and you'll see how the reducer uses more descriptive syntax within. 我们将initialValue设置为new Map()然后您将了解reducer如何在其中使用更多描述性语法。 Note comments aren't even necessary because the code says everything it needs to. 注意注释甚至不是必需的,因为代码说明了它所需要的一切。

 var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza'] var initialValue = new Map() var reducer = function (tally, vote) { if (tally.has(vote)) return tally.set(vote, tally.get(vote) + 1) else return tally.set(vote, 1) } var result = votes.reduce(reducer, initialValue) console.log(Array.from(result.entries())) 

Output 输出量

[
  [ "tacos", 2 ],
  [ "pizza", 3 ],
  [ "fries", 1 ],
  [ "ice cream", 2 ]
]

just for funs 只是为了好玩

I can show you that the visual representation of the sum via reduce is correct/accurate by writing a reducer that builds a string instead of actually adding the numbers 我可以通过编写一个构造字符串而不是实际将数字相加的reduce来向您展示通过reduce进行的总和的视觉表示是正确/准确的

 var initialValue = 0 var reducer = function(a,b) { return '(' + a + ' + ' + b + ')' } var result = [1,2,3].reduce(reducer, initialValue) console.log(result) // (((0 + 1) + 2) + 3) 

This technique might be useful for you when trying to understand/debug your own reducers 尝试了解/调试自己的Reducer时,此技术可能对您有用

The reduce() method reduces the array to a single value . reduce()方法数组缩小单个值

The reduce() method executes a provided function for each value of the array (from left-to-right ). reduce()方法为数组的每个值从左到右 执行 提供的函数

The return value of the function is stored in an accumulator (result/total). 函数的返回值 存储在累加器中(结果/总计)。

You have this given list : 您有此给定列表

var votes = ['tacos','pizza','pizza','tacos','fries','ice cream','ice cream','pizza'];

Then you make an Initial List . 然后创建一个初始列表 You can modify this and the function will be applied for both lists. 您可以对此进行修改,并且该功能将同时应用于两个列表。

var initialValue = {}

"reducer" is initialized as a function . “ reducer”被初始化为一个函数 The reason that we place the function in "reducer" is so we can call it more easily further on. 之所以将函数放置在“ reducer”中,是因为我们可以更轻松地对其进行调用。 You can do whatever you want in this function and it will be executed on the list in the upcoming steps 您可以在此函数中做任何您想做的事,它将在接下来的步骤中在列表中执行

var reducer = function(tally, vote) {
  if (!tally[vote]) {
      tally[vote] = 1;
  } else {
      tally[vote] = tally[vote] + 1;
  }
      return tally;
  }

Finally, the result of the function is stored into the variable. 最后,函数的结果 存储到变量中。

var result = votes.reduce(reducer, initialValue)

Well, let's try to expand the iteration: 好吧,让我们尝试扩展迭代:

When you execute 执行时

votes.reduce(reducer, initialValue)

It actually does this: 它实际上是这样做的:

reducer(initialValue, votes[0]); // step1, return {'tacos': 1}
reducer(returnedValueOfStep1, votes[1]); // step2, return {'tacos': 1, 'pizza': 1}
reducer(returnedValueOfStep2, votes[2]); // step3, return {'tacos': 1, 'pizza': 2}
reducer(returnedValueOfStep3, votes[3]); // step4 ...
reducer(returnedValueOfStep4, votes[4]); // step5 ...
reducer(returnedValueOfStep5, votes[5]); // step6 ...
reducer(returnedValueOfStep6, votes[6]); // step7 ...
reducer(returnedValueOfStep7, votes[7]); // step8 ...

I think it quite clear right now. 我认为现在很清楚。

And usually, if we do not provide initialValue as the second parameter for reduce, it will take the first element of array as the initialValue, and starts iteration from the second one: 通常,如果我们不提供initialValue作为reduce的第二个参数,它将数组的第一个元素作为initialValue,并从第二个元素开始迭代:

reducer(votes[0], votes[1]); // step1 ...
reducer(returnedValueOfStep1, votes[2]); // step2 ...
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM