来自数组JavaScript的总和

时间:2020-02-25 21:27:30

标签: javascript ecmascript-6

我正在尝试获取总买入和卖出的阵列。但是,看起来很难找到方法。

我遍历数组,但是无法以名称显示买卖的总和。

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>

我想要输出:

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

任何帮助将不胜感激。

10 个答案:

答案 0 :(得分:5)

使用Array.reduce并检查第二个条目(操作)以将金额添加到正确的位置:

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);

答案 1 :(得分:3)

您可以将对象作为结果以及获取正确索引的类型。

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; }

答案 2 :(得分:1)

这是您可以做到的一种方法:

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);

答案 3 :(得分:1)

由于其他所有人都在使用函数式编程,因此这是循环的一种旧方法:)

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));

答案 4 :(得分:1)

使用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)

答案 5 :(得分:1)

我认为我会做得更深入,因此您将拥有思想过程,而不仅仅是最终代码。 (此外,我还是个混蛋,喜欢写作。:D)

第1步:考虑函数的总体流程

在查看数据本身之前,首先要考虑的就是查看数据的用途。

首先,您要遍历数组以对其中的每个项目进行一些处理。这建议使用数组中内置的功能之一,例如forEachmapreduce。这些全部遍历数组的元素,将每个元素传递给您定义的函数。但是他们对这些数据做不同的事情。

  • forEach使您可以访问每个元素,但并不希望您输出任何内容,仅出于某种原因使用信息即可。 (您可以更改某些内容,但最好不要使用旧数据并创建新版本,这样一来,您始终知道自己拥有一组新的数据,而不是直接进行调整。这是一个好主意。如果需要调整数据,请使用map,如下所述。)
  • map使您可以访问每个元素,但希望您返回一些内容,以便根据从旧数组中获得的内容创建一个新数组。因此,如果您有一个数字数组,并且想要一个将这些数字转换为字符串的其他数组,则可以创建一个类似(number) => '' + number的函数,将其传递给map,然后您就可以最终会得到一个新数组,其中所有数字都转换为字符串。
  • reduce使您可以访问每个元素,但无需创建新的数组,而是可以组合信息,将其简化简化为某种形式的单个值或对象。这是我们将要使用的方法,因为我们要获取数组中的元素并将其插入到组合了信息的单个对象中。

我们也可以使用for循环来执行此操作,但是通过使用内置函数,我们可以专注于对我们很重要的工作-组合信息-然后数组执行遍历每个项目的内务处理工作。当我们将所有内容都放在下面时,这将变得更加清晰。

第2步:弄清楚如何转换数据

下一步是了解如何转换数据。一旦有了这些,就可以弄清楚如何将条目添加在一起。

如果您查看自己的交易,则每笔交易如下:

[name, buy or sell, amount]

最后想要的是一个对象,其键和值看起来像

name: [buy amount, sell amount]

一旦您看到了,关键就是弄清楚如何从一种安排转到另一种安排。

处理名称非常简单。您只需将其从数组传递给对象,而无需对其进行转换:

const name = transaction[0];

接下来要考虑的是如何将买入和卖出金额划分为单独的字段。如果买入应该在索引0处,卖出应该在索引1处,则可能很简单:

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

最后一项是实际金额:

const amountValue = transaction[2];

然后,忽略如何将它们添加在一起,如果我们有一个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;

第3步:弄清楚如何将条目组合在一起

在第2步中有一些我们未解决的问题

  1. 我们如何仅在尚不存在条目的情况下创建新条目? (我们不想覆盖现有的数组。)
  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

如果我们将它们放在一起,我们将获得如何将数组简化为对象的基本方法:

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

步骤4:创建传递给reduce()的函数

我们几乎拥有完整的 reducer功能。我们只需要添加函数定义并返回值:

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;
}

该函数获取我们要收集的值( accumulator )和数组中的当前元素,并返回更新的累加器。

reduce中使用的任何功能都有两点要记住:

  1. 累加器始终是第一个参数。这一直使我无所适从,因为我认为array元素将是最重要的,因此当然是第一个!但不是。第一个值是从一个元素传递到另一个元素的值,当您通过数组时,该值会累积数据。当您编写更多reducer时,需要注意一些事情。
  2. 总是返回累加器。它将被传递到每个函数调用中,但是如果不返回它,则下一个元素将获得未定义的累加器。如果在化简器中出现TypeError,请检查以确保返回值。

步骤5:将化简函数插入reduce

获得有效交易摘要的最后一步:

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

(我删除了注释以对其进行清理。代码本身非常不言自明,并且注释破坏了最终产品中的流程。)

就是这样。最后一行采用您的数组(此处命名为transactions)并调用其reduce函数。我们给它提供减速器的参考,以及一个初次插入作为resultsObject的初始值。它返回完全填充的resultObject,并以我们想要的方式组合事务。 (如果我们不包含{}作为初始值,则当浏览器抱怨您未定义累加器时,我们将收到另一个TypeError。)

将其与for循环进行比较时,需要注意三件事:

  • 太紧了。没有循环索引可担心,没有条件可检查,没有多余的括号。这是一项功能,只有一行。
  • 这是声明性的。不必阅读循环和汇总数据的所有机制,而只需了解从左到右的内容即可: / p>

    1. 定义一个名为transactionSummary的变量
    2. 查看transactions数组
    3. reduce该数组...
    4. ...使用getTransactionSummary

    通过在函数中定义代码,并将该函数作为参数进行归约,我们几乎可以从代码中创建一个句子。这可以帮助我们提高可读性。 除了使单行简明扼要之外,它还简化了我们的功能。该功能从顶部开始,在一种情况下直接向下工作。我们需要检查的条件越少,我们需要跟踪的循环越少,就越容易跟踪正在发生的事情。

  • 它是可插入的。在这种情况下,我们要创建交易摘要,因此getTransactionSummary对于减少交易量很有用。如果我们要计算购买和出售的总数以获得总交易量,则可以创建一个不同的函数,例如getTransactionVolume。只要使用一个累加器和一个数组元素,并返回更新的累加器,我们就可以用getTransactionSummary替换getTransactionVolume并从同一数据中获得完全不同的统计信息。

这三个元素(尤其是第二个和第三个元素)使函数式编程如此漂亮。关于功能编程及其在JavaScript中的工作方式的文章很多。玩得开心!

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

答案 6 :(得分:0)

您是否正在寻找类似的东西?不过,这可能不是一个很好的解决方案。

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);

答案 7 :(得分:0)

这是您需要的吗?

    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);

答案 8 :(得分:0)

尝试一下:

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
})

答案 9 :(得分:0)

很多不错的选择。这是另一种策略-将其包装在函数中,并根据需要返回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]
});