Summing numbers from 1st array if 2nd array match - javascript

I have 2 arrays that looks like this:
amountArray = ["200","150","500","100"];
currencyArray = ["EUR","EUR","USD","USD"];
I'd like to sum amounts from 1st array if 2nd array match.
Result i'd like to get :
totalAmount = "350 EUR | 600 USD";

You could take a Map for collecting same currencies and get the joined values.
let amounts = ["200", "150", "500", "100"],
currencies = ["EUR", "EUR", "USD", "USD"],
result = Array
.from(
currencies.reduce(
(m, c, i) => m.set(c, (m.get(c) || 0) + +amounts[i]),
new Map
),
([k, v]) => [v, k].join(' ')
)
.join(' | ');
console.log(result);

Store your data in a hashmap with the currencies as keys. Then while looping through your amounts, if the key exists, add to the existing sum.
At the end, convert back to an array and print.
const amountArray = ["200","150","500","100"];
const currencyArray = ["EUR","EUR","USD","USD"];
const result = {};
amountArray.forEach((amt, idx) => {
const amountInt = parseInt(amt, 10);
const currency = currencyArray[idx];
const existingTotal = result[currency] || 0;
result[currency] = existingTotal + amountInt;
});
const resultArray = Object.keys(result).map(key => `${result[key]} ${key}`);
const totalAmount = resultArray.join(' | ');
console.log(totalAmount);

You could do this
amountArray = ["200","150","500","100"];
currencyArray = ["EUR","EUR","USD","USD"];
var res = {}
currencyArray.forEach((elem, index)=>{
res[elem] = res[elem] ? parseInt(res[elem]) + parseInt( amountArray[index]) : parseInt(amountArray[index])
});
console.log(res);
var totalAmount = '';
for(var key in res){
totalAmount += ` ${res[key]} ${key} |`;
}
console.log(totalAmount.substr(0, totalAmount.length-1))

If possible, you can creat a class that contains 2 fields, 1 is amount, 1 is corresponding currency. Then you can group by currency and then do the sum up

amountArray = ["200","150","500","100"];
currencyArray = ["EUR","EUR","USD","USD"];
var totalAmount = [];
var result = amountArray.reduce(function(result, field, index) {
//console.log(field);
if(!(currencyArray[index] in result)){
//console.log("afaff");
result[currencyArray[index]] = 0;
}
result[currencyArray[index]] = result[currencyArray[index]] + parseInt(field);
//console.log(result)
return result;
}, {})
console.log(totalAmount);
//totalAmount = "350 EUR | 600 USD";

You could use reduce function to get the desired result.
let amountArray = ["200","150","500","100"];
let currencyArray = ["EUR","EUR","USD","USD"];
let result = currencyArray.reduce((acc,c,i) => {
if(acc.hasOwnProperty(c)){
return{
...acc,
[c]:parseInt(acc[c])+parseInt(amountArray[i])
}
}else{
return{
...acc,
[c]:amountArray[i]
}
}
},{})
console.log(result)

Use forEach to go over both arrays and build one object with accumulated values.
Then use map and join to make required string.
amountArray = ["200", "150", "500", "100"];
currencyArray = ["EUR", "EUR", "USD", "USD"];
const res = {};
currencyArray.forEach(
(key, i) => (res[key] = (res[key] ?? 0) + Number(amountArray[i]))
);
const str = Object.entries(res)
.map(([key, sum]) => `${sum} ${key}`)
.join(" | ");
console.log(str);

I have used java to solve this..
String[] amountArray = {"200","150","500","100"};
String[] currencyArray = {"EUR","EUR","USD","USD"};
HashMap<String, Integer> map = new HashMap<>();
for(int i =0; i < currencyArray.length;i++)
{
Integer n = Integer.parseInt(amountArray[i]);
Integer old = map.get(currencyArray[i]);
if(old == null)
{
old = new Integer(0);
}
Integer val = n+old;
map.put(currencyArray[i], val);
}

A hashmap solution. The first part forms the hashmap which uses currency as key and amount array as value. The second part constructs the string result. The time complexity is O(n^2), space complexity is O(n). n is the length of amountArray or currencyArray.
const amountArray = ["200","150","500","100"];
const currencyArray = ["EUR","EUR","USD","USD"];
function getTotalAmount() {
// --- First Part ---- //
const map = new Map()
const uniqueCurrencyArray = [];
for (let i = 0; i < currencyArray.length; i++) {
if (!uniqueCurrencyArray.includes(currencyArray[i])) {
uniqueCurrencyArray.push(currencyArray[i]);
}
}
for(const currency of uniqueCurrencyArray) {
const result = []
for(const [index, cur] of currencyArray.entries()) {
if(cur === currency) {
result.push(amountArray[index])
}
}
map.set(currency, result)
}
// --- Second Part -- //
let finalResult = ""
for(const key of map.keys()) {
if(finalResult !== "") {
finalResult += " | "
}
const amountArr = map.get(key)
let totalAmount = 0
for(const amount of amountArr) {
totalAmount += parseInt(amount, 10)
}
finalResult += `${totalAmount} ${key}`
}
return finalResult
}
console.log(getTotalAmount())

Related

how can i put commas in thousands?

`$.ajax({
url : "/selectList.do",
data:{memberNo:memberNo},
success : function(list){
console.log(list);
for(let i=0;i<list.length;i++){
list[i].NUMBER;
}
}
});`
I got numbers from ajax and I want to put a commas in this number in thousands.
How can I do it?
Try use regex
const thousands = (o) => o.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ',');
console.log(thousands(123456789));
console.log(thousands(123456789.123));
Or use Number.prototype.toLocaleString()
const num = 123456.789;
console.log(num.toLocaleString());
Or use Intl.NumberFormat
const number = 123456.789;
const nf = new Intl.NumberFormat('en-US');
console.log(nf.format(number));
Or use Array.prototype
const insert = (arr, index, newItem) => [
...arr.slice(0, index),
newItem,
...arr.slice(index)
];
const thousands = (o) => {
let tmpArr = o.toString().split('.');
let splitArr = tmpArr[0].split('');
const reversed = splitArr.reverse();
for (let i = 1; i <= reversed.length; i++) {
if (i % 3 == 0)
splitArr = insert(splitArr, i, ',');
}
tmpArr[0] = tmpArr.length > 1 ? '.' : '';
return splitArr.reverse().concat(tmpArr).join('');
};
console.log(thousands(123456));
console.log(thousands(123456.789));

How to merge two arrays of dates and keep the order for other array

I have this code:
var dates1 = ['1/2021', '1/2021', '12/2020'];
var values1 = ['-2500', '-150', '-10000'];
var dates2 = ['2/2021', '3/2021', '1/2021'];
var values2 = ['3000', '1000', '3000'];
What I need is to merge the dates1 with dates2, and keep the same order for values1 and values2 adding a 0 for the dates that has none values, so the result would be this:
var dates = ['12/2020', '1/2021', '2/2021', '3/2021'];
var values1 = ['-10000', '-2650', '0', '0'];
var values2 = ['0', '3000', '3000', '1000'];
To merge the arrays of dates I'm using this code:
var dates = dates1.concat(dates2);
I just don't know how can I keep the same order for values1 and values2 adding a 0 for none values.
Any suggestion ? Thank you !
Break down the algorithm into the smallest steps, then order the steps after each other:
const dates1 = ['1/2021', '1/2021', '12/2020'];
const values1 = ['-2500', '-150', '-10000'];
const dates2 = ['2/2021', '3/2021', '1/2021'];
const values2 = ['3000', '1000', '3000'];
// summing the arrays & keeping track of how
// the values should be ordered
const reduceArr = ({ dates, values }) => {
const reduced = dates.reduce((a, c, i) => {
if (typeof a[c] === 'undefined') a[c] = 0
a[c] += Number(values[i])
return a
}, {})
const filteredDates = [...new Set([...dates])]
const filteredValues = filteredDates.map(date => reduced[date])
return {
filteredDates,
filteredValues,
}
}
// merging the different dates arrays
const mergeDates = ({ dates1, dates2 }) => {
return [...new Set([...dates1, ...dates2])]
}
// time-sorting the merged arrays
const sortDates = ({ dates }) => {
return [...dates].sort((a, b) => {
const [m1, y1] = a.split('/')
const [m2, y2] = b.split('/')
return new Date(y1, m1, 1) - new Date(y2, m2, 1)
})
}
// mapping values based on the orders &
// adding 0 if no value is found
const mapToDates = ({ sortedDates, reducedArr }) => {
return sortedDates.map(date => {
const idx = reducedArr.filteredDates.indexOf(date)
return idx === -1 ? 0 : reducedArr.filteredValues[idx]
})
}
// actually executing the steps:
const mergedDates = mergeDates({ dates1, dates2 })
const sortedDates = sortDates({ dates: mergedDates })
const reducedArr1 = reduceArr({ dates: dates1, values: values1 })
const mapValues1 = mapToDates({ sortedDates, reducedArr: reducedArr1 })
const reducedArr2 = reduceArr({ dates: dates2, values: values2 })
const mapValues2 = mapToDates({ sortedDates, reducedArr: reducedArr2 })
console.log('mapValues1', mapValues1)
console.log('mapValues2', mapValues2)
I think that what you need is that:
Array.prototype.unique = function() {
var a = this.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
};
stringToDate = function(str) {
return str.substring(str.search("/")+1, str.search("/")+5) + "-" + (Number(str.substring(0, str.search("/"))) < 10 ? '0' : '') + str.substring(0, str.search("/") ) + "-15T00:00:00Z";
}
dateToString = function(dt) {
dt = new Date(dt);
return (1 + dt.getMonth()) + "/" + dt.getFullYear() ;
}
var dates1 = [stringToDate('1/2021'), stringToDate('1/2021'), stringToDate('12/2020')];
var values1 = ['-2500', '-150', '-10000'];
var dates2 = [stringToDate('2/2021'), stringToDate('3/2021'), stringToDate('1/2021')];
var values2 = ['3000', '1000', '3000'];
var dates_out = dates1.concat(dates2).unique().sort();
var values1_out = new Array(dates_out.length);
var values2_out = new Array(dates_out.length);
dates_out.forEach((dt, i) => {
dates_out[i] = dateToString(dates_out[i]);
values1_out[i] = 0;
values2_out[i] = 0;
dates1.forEach((dt1, i1) => {
if (dt1 === dt) {
if (values1_out[i] != undefined)
values1_out[i] = values1_out[i] + Number(values1[i1]);
else
values1_out[i] = Number(values1[i1]);
}
});
dates2.forEach((dt2, i2) => {
if (dt2 === dt) {
if (values2_out[i] != undefined)
values2_out[i] = values2_out[i] + Number(values2[i2]);
else
values2_out[i] = Number(values2[i2]);
}
});
});
console.log(dates_out);
console.log(values1_out);
console.log(values2_out);
I don't know if this is the best solution. I would create dictionaries to work with the data.
I understood that you need to order the dates (the first result being 12/2020 instead of 1/2021). I also understood that you need the dates as a string, but if you need the date as a datatype, you can remove the part where I convert it back to a string.
here is the solution in python, conversion to javascript should be straight forward. 1. build a list of tuples for dates1/values1 and dates2/values2. 2. Get a list of unique dates. 3. Reduce the tuple lists to a dictionary accumulating on the key which is the date. 4. Using the dates list and the dictionaries create the result value1 and 2 list.
def ReduceToDictionary(tuples):
dict={}
for item in tuples:
key = item[0]
value = item[1]
if key in dict:
dict[key] += float(value)
else:
dict[key] = float(value)
return dict
def BuildList(dates,dict):
result_values=[]
for date in dates:
if date in dict:
val=dict[date]
result_values.append(val)
else:
val=0
result_values.append(val)
return result_values
def StrToDate(string):
groups=re.match('(\d{1,2})[/](\d{4})',string)
year=int(groups[2])
month=int(groups[1])
return(datetime.datetime(year,month,1))
dates1 = ['1/2021', '1/2021', '12/2020']
values1 = ['-2500', '-150', '-10000']
dates2 = ['2/2021', '3/2021', '1/2021']
values2 = ['3000', '1000', '3000']
tuple1=[(StrToDate(dates1[i]),values1[i]) for i in range(len(dates1))]
tuple2=[(StrToDate(dates2[i]),values2[i]) for i in range(len(dates2))]
dates=sorted(set(list(map(StrToDate,dates1))+list(map(StrToDate,dates2))))
dict1=ReduceToDictionary(tuple1)
dict2=ReduceToDictionary(tuple2)
result_values1=BuildList(dates,dict1)
result_values2=BuildList(dates,dict2)
date_string=[date.strftime("%Y/%m") for date in dates]
print(date_string)
print(result_values1)
print(result_values2)
output:
['2020/12', '2021/01', '2021/02', '2021/03']
[-10000.0, -2650.0, 0, 0]
[0, 3000.0, 3000.0, 1000.0]

Create new array with matched values with it's sum in javascript

I have below type of array, now I want to match the value before underscore and sum the values after underscore and store it into the new array with matched key.
let myarray = [];
myarray[0] = "25_5";
myarray[1] = "125_15";
myarray[2] = "25_10";
myarray[3] = "125_30";
Expected output
matchedArr[25] = 15
matchedArr[125] = 45
I tried below code
this.myarray.forEach((i) => {
let arr = i.split("_");
let key = arr[0];
let price = arr[1];
console.log(key+' = '+price);
});
You can do this with a fairly simple reduce
let myarray = [];
myarray[0] = "25_5";
myarray[1] = "125_15";
myarray[2] = "25_10";
myarray[3] = "125_30";
const result = myarray.reduce( (acc, i) => {
const [key,value] = i.split("_");
acc[key] = (acc[key] || 0) + parseInt(value,10);
return acc;
},{})
console.log(result)
This will do sort of what you want
Are you sure you want the output to be an array though?
let myarray = [];
myarray[0] = "25_5";
myarray[1] = "125_15";
myarray[2] = "25_10";
myarray[3] = "125_30";
let matchedArray=myarray.reduce((a,i)=>{
const [k,v]=i.split('_');
a[k]=(a[k]||0)+ +v;
return a;
},[]);
console.log(matchedArray);
if you replace ,[]) with ,{}) you'll get a much more useful result

How to sum and group array based on first value

I need to sum the second value of an array and group it based on the first value (year).
This is my array:
dataArray = [[2020,140],[2020,145],[2020,90],[2021,88],[2021,12]];
And this is my function:
var result = [];
dataArray.reduce(function (res, value) {
if (!res[value[0]]) {
res[value[0]] = [value[0], 0];
dataArray.push(res[value[0]]);
}
res[value[0]][1] += value[1];
return res;
}, {});
I need this result:
dataArray = [[2020,375],[2021,100]]
But I got strange result, I think based on sum of previous value.
Can someone help me?
Thank you
You can simplify the computation by doing:
Object.entries(
dataArray.reduce(function(res, value) {
if (!res[value[0]]) {
res[value[0]] = 0;
}
res[value[0]] += value[1];
return res;
}, {})
);
By the way, your code is working on browser console
you can do that
const
dataArray = [[2020,140],[2020,145],[2020,90],[2021,88],[2021,12]]
, result =
dataArray.reduce((sums,[year,value])=>
{
let sYear = sums.find(x=>x[0]===year)
if (!sYear) sums.push([year,value])
else sYear[1] += value
return sums
},[])
console.log( result )
.as-console-wrapper {max-height: 100%!important;top:0 }
or:
const
dataArray = [[2020,140],[2020,145],[2020,90],[2021,88],[2021,12]]
, result2 =
Object.entries(
dataArray.reduce((sums,[year,value])=>
{
sums[year] = (sums[year] ?? 0) + value
return sums;
}, {}))
console.log( result2 )
A bit more clean solution with JavaScript Map Object
const dataArray = [[2020,140],[2020,145],[2020,90],[2021,88],[2021,12]];
var result = new Map();
dataArray.forEach((el) => {
let val = result.get(el[0]);
if(!val) {
result.set(el[0], el[1])
} else {
result.set(el[0], el[1] + val)
}
})
console.log([...result]);
Probably isn't the best option but I hope it helps you.
let dataArray = [[2020,140],[2020,145],[2020,90],[2021,88],[2021,12]]
const sumOdds = function(arr){
let sum = 0
for(i=0; i<arr.length; i++){
if(i%2 != 0) sum+= arr[i]
}
return sum
}
const twenties = dataArray.filter(arr => arr.includes(2020)).flat()
const twentyOnes = dataArray.filter(arr => arr.includes(2021)).flat()
const twentiesSum = sumOdds(twenties)
const twentyOnesSum = sumOdds(twentyOnes)
dataArray = [[2020, twentiesSum],[2021, twentyOnesSum]]
console.log(dataArray)

Script to group elements where every character is same to each other

For input:
["abc","def","okg","fed","bca"]
expected output should be:
["abc","bca"],["def","fed"],["okg"]
here "abc", "bca" and "def", "fed" contains same character and "okg" there is no element which contains these character
const arr = ["abc", "def", "okg", "fed", "bca"];
let find = (arr) => {
let res = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 1; j < arr.length; j++) {
if (arr[i].search(arr[j])) {
res.push(arr[j]);
}
}
}
return res;
}
console.log(find(arr))
A reduce will do the trick - it seems the shortest code here (apart from the one using lodash)
const arr = ["abc", "def", "okg", "fed", "bca"],
res = Object.values(arr.reduce((acc, ele) => {
const key = ele.split("").sort();
(acc[key] = acc[key] || []).push(ele)
return acc
}, {}))
console.log(res)
.search returns a number indicating the index of where the match was found. Check that the result isn't -1 instead of checking that the result is truthy. But...
.search isn't the right tool here anyway, because it won't find different combinations of the same character. You need a different approach. One way would be to create an object whose keys are the characters found, and the values are the number of occurrences, then use a sorted representation of that object as a key. For example, have both abc and bca turn into something like:
a,1-b,1-c,1
Iterate through the input array, generating a key for each string, and putting the string on an object with that key. At the end, take the object's values.
const strToKey = (str) => {
const grouped = {};
for (const char of str) {
grouped[char] = (grouped[char] || 0) + 1;
}
return Object.entries(grouped)
.sort((a, b) => a[0].localeCompare(b[0]))
.join('-');
};
let find = (arr) => {
const grouped = {};
for (const str of arr) {
const key = strToKey(str);
grouped[key] ??= [];
grouped[key].push(str);
}
return Object.values(grouped);
}
console.log(find(["abc", "def", "okg", "fed", "bca"]));
Another option, when creating the keys, instead of sorting the object afterwards, you could sort the string first:
const strToKey = (str) => {
const grouped = {};
for (const char of [...str].sort()) {
grouped[char] = (grouped[char] || 0) + 1;
}
return Object.entries(grouped).join('-');
};
let find = (arr) => {
const grouped = {};
for (const str of arr) {
const key = strToKey(str);
grouped[key] ??= [];
grouped[key].push(str);
}
return Object.values(grouped);
}
console.log(find(["abc", "def", "okg", "fed", "bca"]));
const input = ["abc","def","okg","fed","bca"]
function getSortedString (str) {
return [...str].sort().join('');
};
function groupBy(input) {
const grouped = [];
while(input.length) {
const nextInput = [];
const first = input[0];
const matched = [first];
for (let i = 1; i < input.length; i++) {
if(getSortedString(first) === getSortedString(input[i])) {
matched.push(input[i])
} else {
nextInput.push(input[i])
}
}
input = nextInput;
grouped.push(matched);
}
console.log(grouped);
}
groupBy(input);
Using Object.values and groupBy (from lodash), you can get a straightforward solution:
You group your array elements by their "sorted" form and then use Object.values to get the output array.
const arr = ["abc", "def", "okg", "fed", "bca"];
const sortString = (str) => str.split("").sort().join("")
const result = Object.values(_.groupBy(arr, sortString));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

Categories

Resources