简体   繁体   English

来自数组 JavaScript 的总和

[英]Sum from array JavaScript

I am trying to get array with total buy and total sell.我正在尝试获得总买入和总卖出的数组。 But, it looks very hard to find way.但是,看起来很难找到方法。

I Iterate over array but, couldn't get any way to display sum of buy and sell with name.我迭代数组但是,无法以任何方式显示带有名称的买卖总和。

 const orders = [ ['AAPL', 'buy', 100], ['GOOG', 'sell', 10], ['AAPL', 'buy', 100], ['AAPL', 'sell', 100], ['AAPL', 'sell', 20], ]; function transform(orders) { const result = {}; orders.forEach(element => { }) return result; }
 <div id="result"></div>

I want output like:我想要这样的输出:

/*
result = {
    // total_buy, total_sell
    'AAPL': [ 200, 120 ],
    'GOOG': [ 0, 10]
}
*/

Any help would be greatly appreciated.任何帮助将不胜感激。

Use Array.reduce and check for the second entry ( action ) to add the amount to the right position :使用Array.reduce并检查第二个条目( action )以将金额添加到正确的位置:

 const orders = [ ["AAPL", "buy", 100], ["GOOG", "sell", 10], ["AAPL", "buy", 100], ["AAPL", "sell", 100], ["AAPL", "sell", 20] ]; const result = orders.reduce((acc, [key, action, amount]) => { acc[key] = acc[key] || [0, 0]; if (action === "buy") acc[key][0] += amount; if (action === "sell") acc[key][1] += amount; return acc; }, {}); console.log(result);

You could take an object as result and the type for getting the right index.您可以将对象作为结果以及获取正确索引的类型。

 function transform(orders) { return orders.reduce((result, [key, type, value]) => { result[key] = result[key] || [0, 0]; result[key][{ buy: 0, sell: 1 }[type]] += value; return result; }, {}); } const orders = [['AAPL', 'buy', 100], ['GOOG', 'sell', 10], ['AAPL', 'buy', 100], ['AAPL', 'sell', 100], ['AAPL', 'sell', 20]]; console.log(transform(orders));
 .as-console-wrapper { max-height: 100% !important; top: 0; }

Here is one way you could do it:这是您可以做到的一种方法:

 const orders = [ ['AAPL', 'buy', 100], ['GOOG', 'sell', 10], ['AAPL', 'buy', 100], ['AAPL', 'sell', 100], ['AAPL', 'sell', 20], ]; const result = {}; orders.map((order) => { const [ tag, type, amt ] = order; if (!result[tag]) result[tag] = [0, 0]; if (type == "buy") result[tag] = [result[tag][0] + amt, result[tag][1]]; if (type == "sell") result[tag] = [result[tag][0], result[tag][1] + amt]; }); console.log(result);

Since everyone else is going with functional programming, here is an old fashion for loop :)由于其他人都在进行函数式编程,因此这是一种老式的 for 循环 :)

const orders = [
    ['AAPL', 'buy', 100],
    ['GOOG', 'sell', 10],
    ['AAPL', 'buy', 100],
    ['AAPL', 'sell', 100],
    ['AAPL', 'sell', 20]
];

function transform(orders) {
    const result = {};

    for (let i = 0; i < orders.length; i++) {
        const [key, op, val] = orders[i];

        if (!result[key]) { result[key] = [0, 0]; }

        result[key][op === 'buy' ? 0 : 1] += val;
    }

    return result;
}

console.log(transform(orders));

Use Array.reduce()使用Array.reduce()

 const transform = () => { const orders = [ ['AAPL', 'buy', 100], ['GOOG', 'sell', 10], ['AAPL', 'buy', 100], ['AAPL', 'sell', 100], ['AAPL', 'sell', 20], ]; return orders.reduce((acc, order) => { const isBuyOption = order[1] === 'buy'; if (Array.isArray(acc[order[0]])) { acc[order[0]][0] = acc[order[0]][0] + (isBuyOption ? order[2] : 0) acc[order[0]][1] = acc[order[0]][1] + (!isBuyOption ? order[2] : 0) } else { acc[order[0]] = [ isBuyOption ? order[2] : 0, !isBuyOption ? order[2] : 0 ]; } return acc; }, {}); } const result = transform(); console.log(result)

I figured I'd go deep, so you'd have the thought process, not just the final code.我想我会深入研究,所以你会有思考过程,而不仅仅是最终的代码。 (Also I'm a wordy bastard and love writing. :D ) (而且我是一个罗嗦的混蛋,喜欢写作。:D)

Step 1: Consider the overall flow of your function第 1 步:考虑函数的整体流程

The first thing to consider, before even looking at the data itself, is looking at what you want to do with the data.在查看数据本身之前,首先要考虑的是查看您想对数据做什么。

First off, you want to loop through the array to do some stuff with each item in it.首先,您要遍历数组以对其中的每个项目执行一些操作。 This suggests using one of the functions built into arrays, such as forEach or map or reduce .这建议使用内置于数组中的函数之一,例如forEachmapreduce These all loop through the array's elements, passing each element to a function you define.这些都循环遍历数组的元素,将每个元素传递给您定义的函数。 But they do different things with that data.但是他们用这些数据做不同的事情。

  • forEach gives you access to each element, but doesn't expect you to output anything, just using the information for some reason. forEach允许您访问每个元素,但不希望您输出任何内容,只是出于某种原因使用信息。 (You can change things, but it's considered a good idea to leave old data alone and create a new version, so that you always know you've got a fresh set of data, instead of tweaking things directly. If you need to tweak the data, use map , described next.) (您可以更改内容,但最好不要理会旧数据并创建新版本,以便您始终知道您拥有一组新数据,而不是直接调整内容。如果您需要调整数据数据,使用map ,接下来描述。)
  • map gives you access to each element, but it expects you to return something, to create a new array based on what you got from the old array. map允许您访问每个元素,但它希望您返回一些内容,以根据您从旧数组中获得的内容创建一个新数组。 So if you, say, have an array of numbers, and you want a different array that has those numbers converted to strings, you could create a function like (number) => '' + number , pass it to map , and then you'd end up with a new array with all of your numbers converted to strings.因此,如果您有一个数字数组,并且您想要一个将这些数字转换为字符串的不同数组,您可以创建一个类似(number) => '' + number的函数,将其传递给map ,然后您最终会得到一个新数组,其中所有数字都转换为字符串。
  • reduce gives you access to each element, but instead of creating a new array, it lets you combine the information, reducing it to some form of single value or object. reduce使您可以访问每个元素,但它不是创建一个新数组,而是让您组合信息,减少为某种形式的单个值或对象。 This is the method we're going to use, because we want to take the elements in the array and plug them into a single object that combines the information.这是我们将要使用的方法,因为我们想要获取数组中的元素并将它们插入到组合信息的单个对象中。

We could have used a for loop to do this, too, but by using the built-in functions, we can focus on just the work that is important to us -- combining the information -- and let the array do the housekeeping work of looping through each item.我们也可以使用for循环来做到这一点,但是通过使用内置函数,我们可以只专注于对我们重要的工作——组合信息——并让数组完成循环遍历每个项目。 This will get clearer as we put everything together below.当我们将所有内容放在一起时,这将变得更加清晰。

Step 2: Figure out how to transform your data第 2 步:弄清楚如何转换数据

The next step is knowing how you want to transform your data.下一步是了解您希望如何转换数据。 Once you have that, then you can figure out how to add the entries together.一旦有了它,您就可以弄清楚如何将条目添加在一起。

If you look at your transactions, each transaction looks like:如果您查看您的交易,每笔交易看起来像:

[name, buy or sell, amount]

What you want at the end is an object with keys and values that look like最后你想要的是一个键和值看起来像的对象

name: [buy amount, sell amount]

Once you've seen that, the key is figuring out how to get from one arrangement to the other.一旦你看到了这一点,关键是弄清楚如何从一种安排到另一种安排。

Handling the name is pretty straightforward.处理名称非常简单。 You'll just pass it from the array to the object, without any need to transform it:您只需将它从数组传递给对象,无需任何转换:

const name = transaction[0];

The next thing to consider is how to split the buy and sell amounts into separate fields.接下来要考虑的是如何将买入和卖出金额拆分为单独的字段。 If buys should be at index 0, and sells at index 1, it could be as simple as:如果应该在指数 0 处买入,并在指数 1 处卖出,则可能很简单:

const amountIndex = transaction[1] === 'buy' ? 0 : 1;

The last item is the actual amount:最后一项是实际金额:

const amountValue = transaction[2];

Then, ignoring how to add these together, if we had a resultsObject to plug this into, we end up with然后,忽略如何将这些加在一起,如果我们有一个resultsObject将其插入,我们最终会得到

const name = transaction[0];
const amountIndex = transaction[1] === 'buy' ? 0 : 1;
const amountValue = transaction[2];

// create a new array with starting values
resultsObject[name] = [0, 0];
// put the transaction's value in the right place
resultsObject[name][amountIndex] = amountValue;

Step 3: Figure out how to combine the entries together第 3 步:弄清楚如何将条目组合在一起

There's a few things we didn't address in step 2:我们在第 2 步中没有解决一些问题:

  1. How do we only create new entries if an entry doesn't exist yet?如果条目尚不存在,我们如何仅创建新条目? (We don't want to overwrite an existing array.) (我们不想覆盖现有数组。)
  2. How do we add values to an existing array?我们如何向现有数组添加值?

This is actually straightforward, but good to consider in its own place, because without it, our results would be completely messed up.这实际上很简单,但最好单独考虑,因为没有它,我们的结果将完全混乱。

The first question is answered by replacing the creation line above with:第一个问题的回答是将上面的创建行替换为:

// create a new array with starting values (if it doesn't already exist)
if (! resultsObject[name]) {
  resultsObject[name] = [0, 0];
}

The second question is answered by performing addition and assignment in the next line:通过在下一行执行加法和赋值来回答第二个问题:

// add the transaction's value to the right place
resultsObject[name][amountIndex] += amountValue; // added the + sign

If we put this together, we have the basic meat of how we want to reduce the array into our object:如果我们把它们放在一起,我们就有了如何将数组减少到我们的对象中的基本内容:

const name = transaction[0];
const amountIndex = transaction[1] === 'buy' ? 0 : 1;
const amountValue = transaction[2];

// create a new array with starting values (if it doesn't already exist)
if (! resultsObject[name]) {
  resultsObject[name] = [0, 0];
}
// add the transaction's value to the right place
resultsObject[name][amountIndex] += amountValue; // added the + sign

Step 4: Create the function we pass to reduce()第 4 步:创建我们传递给reduce()的函数

We almost have the entire reducer function built.我们几乎已经构建了整个减速器功能 We just have to add the function definition and return value:我们只需要添加函数定义和返回值:

const getTransactionSummary = (resultsObject, transaction) => {
  const name = transaction[0];
  const amountIndex = transaction[1] === 'buy' ? 0 : 1;
  const amountValue = transaction[2];

  // create a new array with starting values (if it doesn't already exist)
  if (! resultsObject[name]) {
    resultsObject[name] = [0, 0];
  }
  // add the transaction's value to the right place
  resultsObject[name][amountIndex] += amountValue; // added the + sign

  return resultsObject;
}

The function takes the value we're collecting (the accumulator ) and the current element in the array, and returns the updated accumulator.该函数采用我们正在收集的值(累加器)和数组中的当前元素,并返回更新后的累加器。

There are two key things to remember about any function you use in reduce :关于你在reduce使用的任何函数,有两个关键的事情要记住:

  1. The accumulator is always the first argument.累加器始终是第一个参数。 This used to throw me off all the time, because I thought the array element would be the most important thing, so of course it's first!这曾经一直让我失望,因为我认为数组元素是最重要的,所以当然是第一位! But no.但不是。 The first value is the one being passed from element to element, the one accumulating data as you go through the array.第一个值是从一个元素传递到另一个元素的值,它在您遍历数组时累积数据。 Something to keep track of as you write more reducers.当你编写更多的 reducer 时要跟踪的东西。
  2. Always return the accumulator.始终返回蓄能器。 It's going to be passed along into each function call, but if you don't return it, the next element will get an undefined accumulator.它将被传递到每个函数调用中,但是如果您不返回它,下一个元素将获得一个未定义的累加器。 If you get a TypeError in a reducer, check to make sure you're returning a value.如果您在减速器中遇到 TypeError,请检查以确保您正在返回一个值。

Step 5: Plug the reducer function into reduce第五步:将reducer函数插入reduce

The final step to get a working transaction summary:获取工作交易摘要的最后一步:

const getTransactionSummary = (resultsObject, transaction) => {
  const name = transaction[0];
  const amountIndex = transaction[1] === 'buy' ? 0 : 1;
  const amountValue = transaction[2];

  if (! resultsObject[name]) {
    resultsObject[name] = [0, 0];
  }
  resultsObject[name][amountIndex] += amountValue;

  return resultsObject;
}

const transactionSummary = transactions.reduce(getTransactionSummary, {});

(I removed the comments to clean it up a bit. The code itself is pretty self-explanatory, and the comments broke up the flow in the final product.) (我删除了注释以稍微清理一下。代码本身是不言自明的,注释破坏了最终产品中的流程。)

That's it.就是这样。 That last line takes your array (named transactions here) and calls its reduce function.最后一行获取您的数组(此处命名为transactions )并调用其reduce函数。 We give it the reference to our reducer, and an initial value to plug in as the resultsObject the first time around.我们给它提供了对我们的 reducer 的引用,以及一个初始值作为第一次插入的 resultsObject。 It returns the fully populated resultsObject, with the transactions combined the way we want.它返回完全填充的 resultsObject,并以我们想要的方式组合交易。 (If we didn't include the {} as an initial value, we'd get another TypeError when the browser complained that you didn't have an accumulator defined.) (如果我们不包括{}作为初始值,当浏览器抱怨您没有定义累加器时,我们会得到另一个 TypeError。)

There are three things to notice when you compare this to a for loop:将其与for循环进行比较时,需要注意三件事:

  • It's tight.很紧。 There's no loop index to worry about, no condition to check, no extra brackets.无需担心循环索引,无需检查条件,无需额外的括号。 It's one function, and one line.这是一个功能,一行。
  • It's declarative.它是声明性的。 Instead of having to read all of the mechanics of looping and aggregating data, you get an idea of what's going on, simply by reading left-to-right:您不必阅读循环和聚合数据的所有机制,只需从左到右阅读即可了解正在发生的事情:

    1. Define a variable named transactionSummary定义一个名为transactionSummary的变量
    2. Look at the transactions array查看transactions数组
    3. reduce that array... reduce那个数组...
    4. ...using getTransactionSummary ...使用getTransactionSummary

    By defining our code in a function, and plugging that function in as an argument to reduce, we can almost create a sentence out of our code.通过在函数中定义我们的代码,并将该函数作为reduce的参数插入,我们几乎可以从我们的代码中创建一个句子。 That can help us improve readability.这可以帮助我们提高可读性。 In addition to making that single line concise, it also simplifies our function.除了使那一行简洁之外,它还简化了我们的功能。 The function starts at the top and works straight down, with one condition.该函数从顶部开始并在一个条件下直接向下工作。 The fewer conditions we need to check, the fewer loops we need to track, the easier it is to keep track of what's going on.我们需要检查的条件越少,我们需要跟踪的循环就越少,跟踪正在发生的事情就越容易。

  • It's pluggable.它是可插拔的。 In this case, we want to create a transaction summary, so getTransactionSummary is useful for reducing our transactions.在这种情况下,我们想要创建一个交易摘要,因此getTransactionSummary可用于减少我们的交易。 If we wanted to count the total number of buys and sells to get the overall volume, we could create a different function, say, getTransactionVolume .如果我们想计算买入和卖出的总数以获得总交易量,我们可以创建一个不同的函数,比如getTransactionVolume As long as it takes an accumulator and an array element, and returns the updated accumulator, we can replace getTransactionSummary with getTransactionVolume and get completely different statistics from the same data.只要它需要一个累加器和一个数组元素,并返回更新后的累加器,我们就可以用getTransactionSummary替换getTransactionVolume并从相同的数据中获得完全不同的统计信息。

These three elements (especially the second and third ones) are what makes functional programming so nifty.这三个元素(尤其是第二个和第三个元素)使函数式编程变得如此漂亮。 There are a whole bunch of articles on what functional programming is, and how it works in JavaScript.有很多关于函数式编程是什么以及它如何在 JavaScript 中工作的文章。 Have fun googling!玩得开心谷歌搜索!

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array /降低

Are you looking for something like this?你在寻找这样的东西吗? It is probably not an elegant solution though.不过,这可能不是一个优雅的解决方案。

 const orders = [ ['AAPL', 'buy', 100], ['GOOG', 'sell', 10], ['AAPL', 'buy', 100], ['AAPL', 'sell', 100], ['AAPL', 'sell', 20], ]; function transform(orders) { const result = {}; orders.forEach(([transaction, type, amount]) => { if (!result[transaction]) { result[transaction] = [0, 0]; } result[transaction][type === 'buy' ? 0 : 1] += amount; }) return result; } let result = transform(orders); console.log(result);

Is this what you needed?这是你需要的吗?

 const orders = [ ['AAPL', 'buy', 100], ['GOOG', 'sell', 10], ['AAPL', 'buy', 100], ['AAPL', 'sell', 100], ['AAPL', 'sell', 20], ]; function transform(orders) { var totalBuy = 0, totalSell = 0; orders.map(order => { if (order[1] == 'buy') totalBuy += order[2]; else if (order[1] == 'sell') totalSell += order[2]; }) console.log({totalBuy, totalSell}) } transform(orders);

Try this:尝试这个:

const data = {};
orders.forEach(innerArray => {
    const [product, action, price] = innerArray;
    data[product] = data[product] || [0, 0]

    data[product][action === 'buy' ? 0 : 1] += +price

    return data
})

Lot's of fine options to choose from.有很多不错的选择可供选择。 Here's another strategy - wrap it in a function and return the results object if you'd prefer.这是另一种策略 - 将其包装在一个函数中,并根据需要返回results对象。

let results = {};

orders.forEach(order => {
    if(!results[order[0]]) results[order[0]] = [0, 0];
    order[1] === 'buy' ? results[order[0]][0] += order[2] :
                         results[order[0]][1] += order[2]
});

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

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