Сумма из массива JavaScript - PullRequest
       4

Сумма из массива JavaScript

2 голосов
/ 26 февраля 2020

Я пытаюсь получить массив с общей покупкой и общей продажей. Но, кажется, очень трудно найти способ.

Я перебираю массив, но не могу найти способ отобразить сумму покупки и продажи с именем.

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 ]

5 голосов
/ 26 февраля 2020

Используйте 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);
3 голосов
/ 26 февраля 2020

Вы можете взять объект как результат и тип для получения правильного индекса.

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; }
1 голос
/ 26 февраля 2020

Я решил, что у меня будет go глубина, так что у вас будет мыслительный процесс, а не только окончательный код. (Также я многословный ублюдок и люблю писать.: D)

Шаг 1: Рассмотрим общий поток вашей функции

Первое, что нужно рассмотреть, прежде чем даже смотреть на сами данные , смотрит на то, что вы хотите сделать с данными.

Прежде всего, вы хотите l oop через массив, чтобы сделать некоторые вещи с каждым элементом в нем. Это предполагает использование одной из функций, встроенных в массивы, таких как forEach или map или reduce. Все это l oop через элементы массива, передавая каждый элемент определенной вами функции. Но они делают разные вещи с этими данными.

  • forEach дает вам доступ к каждому элементу, но не ожидает, что вы что-либо выведете, просто по какой-то причине используя информацию. (Вы можете что-то изменить, но считается хорошей идеей оставить старые данные в покое и создать новую версию, чтобы вы всегда знали, что у вас есть свободный набор данных sh вместо прямой настройки. Если вам нужно чтобы настроить данные, используйте map, описанный ниже.)
  • map дает вам доступ к каждому элементу, но ожидает, что вы что-то вернете, чтобы создать новый массив на основе того, что вы получили из старый массив. Так что, если у вас, скажем, есть массив чисел, и вы хотите другой массив, в котором эти числа преобразуются в строки, вы можете создать функцию, такую ​​как (number) => '' + number, передать ее в map, и тогда вы получите с новым массивом, в котором все ваши числа преобразованы в строки.
  • reduce дает вам доступ к каждому элементу, но вместо создания нового массива позволяет объединять информацию, сокращая это в какой-то форме одного значения или объекта. Это метод, который мы собираемся использовать, потому что мы хотим взять элементы в массиве и подключить их к единому объекту, который объединяет информацию.

Мы могли бы использовать for l oop, чтобы сделать это тоже, но используя встроенные функции, мы можем сосредоточиться только на работе, которая важна для нас - объединение информации - и позволить массиву выполнять служебную работу, проходя по каждому вещь. Это станет более понятным, когда мы соберем все вместе ниже.

Шаг 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()

У нас почти полностью встроена функция редуктора . Нам просто нужно добавить определение функции и возвращаемое значение:

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

Функция принимает собираемое нами значение (аккумулятор ) и текущий элемент в массиве и возвращает обновленный аккумулятор.

О любой функции, которую вы используете в reduce, следует помнить две ключевые вещи:

  1. Аккумулятор всегда является первым аргументом. Раньше это все время сбрасывало меня, потому что я думал, что элемент массива будет самой важной вещью, поэтому, конечно, он первый! Но нет. Первое значение - это то, которое передается от элемента к элементу, а накапливает данные, когда вы go проходите через массив. Что-то, что нужно отслеживать, когда вы пишете больше редукторов.
  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, с транзакциями, объединенными так, как мы хотим. (Если бы мы не включили {} в качестве начального значения, мы получили бы еще одну ошибку TypeError, когда браузер пожаловался, что у вас не определен аккумулятор.)

Есть три вещи, на которые следует обратить внимание, когда Вы сравниваете это с for l oop:

  • Туго. Нет индекса l oop, о котором нужно беспокоиться, нет условий для проверки, нет дополнительных скобок , Это одна функция и одна строка.
  • Это декларативно. Вместо того, чтобы читать всю механику зацикливания и агрегирования данных, вы получаете представление о том, что происходит, просто читая слева направо:

    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

1 голос
/ 26 февраля 2020

Использование 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)
1 голос
/ 26 февраля 2020

Поскольку все остальные занимаются функциональным программированием, вот старая мода для l oop :)

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));
1 голос
/ 26 февраля 2020

Вот один из способов сделать это:

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);
0 голосов
/ 26 февраля 2020

Много прекрасных вариантов на выбор. Вот еще одна стратегия - оберните ее в функцию и, если хотите, верните объект 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]
});
0 голосов
/ 26 февраля 2020

Попробуйте это:

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
})
0 голосов
/ 26 февраля 2020

Это то, что вам нужно?

    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);
0 голосов
/ 26 февраля 2020

Вы ищете что-то подобное? Это, вероятно, не элегантное решение.

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...