Add/sum multiple values in array with same id - javascript

So lets say i have the following array.
[{idProduct:1, unitCost:400},
{idProduct:1, unitCost:160},
{idProduct:1, unitCost:46},
{idProduct:2, unitCost:200},
{idProduct:2, unitCost:40}
I cant seem to find the way to add the unit cost of product 1 and then cut off to add the other units cost of product 2 and so on... I actually want to append it to a different row in google spreadsheet but I first want to calculate it.
I tried some for/if loops but i always end up with the total cost for all products, not just individual ones.
This for gives out the total cost for all ids. When I palce an if inside this for, Im not sure how to compare the two ids, plus Im supposed to set totalCost back to 0 if i want to reset the sum
for (var a = 0; a < arr.length ; a++) {
totalCost= totalCost+ arr[a].unitCost;
}
I tried an if with a break but that doesnt seem to work either, wanted to maybe try promises but Im not sure that would help. I also tried to set another for that compares the next ids to the one im currently in but that seemed to complicate things and the numbers i got were wrong.
I also tried
for (var a = 0; a < arr.length ; a++) {
if(arr[a].idProduct === arr[a+1].idProduct){
totalCost= totalCost+ arr[a].unitCost;
}
}
But of course on the last id it compares it to undefinded since a+1 is longer than the length of the array.
Im honestly burned out by this by now, and im pretty sure its a simple solution, but I really dont know what else to do

You can use reduce to summarize the array and add the values into an object using the idProduct as the key. Use Object.values to convert the object into an array.
let arr = [{"idProduct":1,"unitCost":400},{"idProduct":1,"unitCost":160},{"idProduct":1,"unitCost":46},{"idProduct":2,"unitCost":200},{"idProduct":2,"unitCost":40}]
let result = Object.values(arr.reduce((c, {idProduct,unitCost}) => {
c[idProduct] = c[idProduct] || {idProduct,unitCost: 0};
c[idProduct].unitCost += unitCost;
return c;
}, {}));
console.log( result );
Or you can use the idProduct as the key like and the sum as the value like:
let arr = [{"idProduct":1,"unitCost":400},{"idProduct":1,"unitCost":160},{"idProduct":1,"unitCost":46},{"idProduct":2,"unitCost":200},{"idProduct":2,"unitCost":40}]
let result = arr.reduce((c, {idProduct,unitCost}) => {
c[idProduct] = c[idProduct] || 0;
c[idProduct] += unitCost;
return c;
}, {});
console.log(result);

You could use a .forEach() like below. This code adds e.unitCost to the object with the same idProduct
var input = [{
idProduct: 1,
unitCost: 400
},
{
idProduct: 1,
unitCost: 160
},
{
idProduct: 1,
unitCost: 46
},
{
idProduct: 2,
unitCost: 200
},
{
idProduct: 2,
unitCost: 40
}
];
var output = { };
input.forEach(e => output[e.idProduct] = (output[e.idProduct] || 0) + e.unitCost);
console.log(output);

let pro;
let unitcost=[];
for (var a = 0; a < arr.length ; a++) {
if(pro==arr[a].idProduct){
unitcost[unitcost.length-1]+=arr[a].unitCost;
}
else{
pro=arr[a].idProduct;
unitcost.push(pro);
unitcost.push(arr[a].unitCost);
}
}
console.log(unitcost);

Related

How do I get my 'for loop' to return the characters I am trying to push?

I am learning the fundamentals of JavaScript currently but am realizing there are definite gaps in my knowledge. I recently started attempting challenges on Codewars when this issue became much more apparent. My latest struggle has been attempting to get this 'for loop' to push characters into an array of numbers in order to format it like a phone number. As many different solutions as I have tried, none of them actually do what I am trying to accomplish. Any help figuring out exactly where I'm going wrong here and what holes are in my logic would be appreciated. My best attempt is this:
const createPhoneNumber = (phoneNumber) => {
let formattedNumber = [];
formattedNumber.push(phoneNumber)
for (let i = 0; i < formattedNumber.length; i++) {
if (formattedNumber[i] === 0) {
formattedNumber.push('(')
}
if (formattedNumber[i] === 2) {
formattedNumber.push(')')
}
if (formattedNumber[i] === 5) {
formattedNumber.push('-')
}
}
return(formattedNumber.toString());
}
console.log(createPhoneNumber(1234567890));
Some feedback:
You're inserting one item into the array formattedNumber.push(phoneNumber) then looping through it, so there's only one iteration
Instead, you could convert the number to a string and iterate using its length
The check formattedNumber[i] === 0 is comparing the value to 0 (this check fails and is why your function is returning the unformatted phone number) but you want to compare the index, so change this to i === 0
At the end of the function you're using toString() to join the characters back together but this will include commas between values, instead use .join('')
const createPhoneNumber = (phoneNumber) => {
const phoneNumberStr = (phoneNumber).toString();
let formattedNumber = [];
for (let i = 0; i < phoneNumberStr.length; i++) {
if (i === 0) {
formattedNumber.push('(')
}
if (i === 2) {
formattedNumber.push(')')
}
if (i === 5) {
formattedNumber.push('-')
}
formattedNumber.push(phoneNumberStr[i]);
}
return(formattedNumber.join(''));
};
console.log(createPhoneNumber(1234567890))
Also, you can use .reduce() to achieve the same thing, it's a convenient function that iterates through an array, and passes a value from one iteration to the next:
const createPhoneNumber = (phoneNumber) =>
(phoneNumber).toString().split('').reduce((acc, char, i) => {
let pre = '';
if (i == 0) { pre = '('; }
if (i == 2) { pre = ')'; }
if (i == 5) { pre = '-'; }
return `${acc}${pre}${char}`;
}, '');
console.log(createPhoneNumber(1234567890));
BTW, I think your question was downvoted because you didn't provide an expected output or more details of the error 😉

Removing rows with 0

I am working with tables and I want to remove all rows that have 0s on them. I coded the following for table to do so.
// eliminating null elements
var k= 0;
for (var i =0; i<operations_row;i++){
if (Total_Ocurrances[i]!=0) {
Cause_code_final[k]= Cause_Row_Operations[i];
Des_final[k]= Description[i];
Total_DT_final[k]= Total_DT[i];
Total_O_final[k]= Total_Ocurrances[i];
k= k +1;
}
}
The variables are all in number format. this is supposed to save a new value into each column every time there is no 0 on the occurrences row, for some reason not all 0s get taken out and some non-0 elements get lost as well.
I don't know your entire code, but I believe that if possible you should work with objects and use the filter method in your array.
var arr = [
{
Total_Ocurrances=1,
Cause_code_final=10,
Des_final='asdfasf',
Total_DT_final=new Date(some_value),
Total_O_final=100
},
{
Total_Ocurrances=0,
Cause_code_final=12,
Des_final='qwerqwer',
Total_DT_final=new Date(another_value),
Total_O_final=1002
}
]
var finalArr = arr.filter((item) => {
return item.Total_Ocurrances != 0;
});

Name value pair list, unable to increment name width number

I'm trying to create this using a for loop.
slideArr.slide1 = 1;
slideArr.slide2 = 2;
slideArr.slide3 = 3;
So I get my total slides, loop over them like so
for ( index = 0; index < totalSlides.length; ++index )
{
slideArr.slide = index;
}
but I want the name value pair name in the case "slide" to increment as well.
for ( index = 0; index < totalSlides.length; ++index )
{
slideArr.slide1 = 1;
}
and on the second loop
for ( index = 0; index < totalSlides.length; ++index )
{
slideArr.slide2 = 2;
}
..etc..
is this possible?
I'm basically creating a name value pair list.
I would highly advise against solutions recommending slideArr["slide"+index]. This is a Code Smell and in this case it suggests you're doing something wrong. Posting your full code would help others give you better, more precise answers.
First, slideArr, to me, implies you're using an Array datatype, but you're treating it more like an Object when you call
slideArr.slide1 = 1;
If it's actually an Array, this would be pretty bad
// Don't use arrays like this !
var slideArr = [];
slideArr.slide1 = 1;
Instead, if you have an Object containing an array of slides, that might be a little better
// Use an object with an array !
var myData = {slides: []};
// Add some slides
myData.slides.push(1);
myData.slides.push(2);
myData.slides.push(3);
Now you have an array of slides within myData
console.log(myData.slides);
// => [1, 2, 3]
You can loop through that quite easily
for (var i=0; i<myData.slides.length; i++) {
console.log(myData.slides[i]);
}
Output
1
2
3
If you know the slides up front, you can define myData all in one go
var myData = {slides: [1, 2, 3]};
You can skip the .push calls above. Looping stays the same and you'll get identical output.
You can do:
slideArr["slide" + index] = index;
but I would like to add this looks weird. Are you sure this is what you want?
How about:
slideArray.slides.push(totalSlides[i]);
Try this
for ( index = 0; index < totalSlides.length; ++index )
{
slideArr["slide" + index] = index;
}

Recursively constructing a JavaScript array of all possible combinations while respecting order

I am having difficulty getting the following concept in to code:
Let's say we are given the following array:
[
'h1,h2',
'span,style'
]
From this I wish to get the following output:
[
'h1 span',
'h1 style',
'h2 span',
'h2 style
]
So that we have an array of strings containing all combinations of the original array, which also respects order (so span h1 and style h2 are not valid).
To describe verbose: I have a single level array of strings which are effectively comma separated values. I wish to iterate over this array and split these strings by their comma in to a new array, and for each index in this new array build a new string which contains all the other split values from subsequent indexes in the original array.
I am having difficulty trying to program this in JavaScript. I understand that I will need some recursion, but I'm confused about how to do it. After trying various different and failing methods, I currently have this:
function mergeTagSegments(arr, i, s) {
i = i || 0;
s = s || '';
if(!arr[i]) { return s; }
var spl = arr[i].split(',');
for(var j in spl) {
s += spl[j] + mergeTagSegments(arr, i+1, s);
}
return s;
}
This also fails to work as intended.
I feel a little embarrassed that I am unable to complete what I originally thought was such a simple task. But I really hope to learn from this.
Many thanks in advance for your advice and tips.
Your thinking along the right lines. Recursion is definetly the way to go. I have implemented a suggested solution below, which should give you the desired output.
var values = ['h1,h2', 'span,style'];
function merge(input, index) {
var nextIndex = index + 1;
var outputArray = [];
var currentArray = [];
if(index < input.length) {
currentArray = input[index].split(',');
}
for(var i = 0, end = currentArray.length; i < end; i++) {
if(nextIndex < input.length) {
merge(input, nextIndex).forEach(function(item) {
outputArray.push(currentArray[i] + ' ' + item);
});
}
else {
outputArray.push(currentArray[i]);
}
}
return outputArray;
}
var output = merge(values, 0, '');
console.log(output);

JSON.stringify() causing an infinite loop (Edit: NO. Bad logic is.)

My product object looks somewhat like this:
{name: 'abc', description: 'def', price: 100, quantity: 1, comment: '', customizations: []}
The customizations key is an array that has other such product objects in it. You may ignore it for this question. As you might have noticed, the comment and customizations keys are the keys that make the (theoretically) same product (practically) different when adding to cart.
I want to make a function to add such products to an array called cart_items[]. If the (practically) same product is chosen, I only want to increment the quantity inside the cart_items[i], else add a new object.
This is my function:
$scope.add_to_cart = function(product) {
// if the cart is empty, skip the brouhaha
if ($scope.cart_items.length === 0) {
$scope.cart_items.push(angular.copy(product));
} else {
for (var i = 0; i < $scope.cart_items.length; i++) {
// copy the original quantity and set it to 1 for comparison
var qty = $scope.cart_items[i].quantity;
$scope.cart_items[i].quantity = 1;
if (JSON.stringify(product) === JSON.stringify($scope.cart_items[i])) {
$scope.cart_items[i].quantity = qty + 1;
} else {
$scope.cart_items[i].quantity = qty;
$scope.cart_items.push(angular.copy(product));
}
}
}
};
The problem: First product adds successfully. Adding another causes an infinite loop. I replaced if(JSON...) with if(1 === 1) and the infinite loop didn't occur. I don't know where am I going wrong. Any help?
The problem you have is that you're increasing the size of the array in the loop and the stop condition is i being $scope.cart_items.length.
If your goal is to add the object if it's not yet present, what you want is probably this :
boolean found = false;
for (var i = 0; i < $scope.cart_items.length; i++) {
var qty = $scope.cart_items[i].quantity;
$scope.cart_items[i].quantity = 1;
if (JSON.stringify(product) === JSON.stringify($scope.cart_items[i])) {
$scope.cart_items[i].quantity = qty + 1;
found = true;
break;
}
}
if (!found) {
var item = angular.copy(product);
item.quantity = 1;
$scope.cart_items.push();
}
Note that two identical objects (i.e. objects with same property values) should not give the same JSON string because the order of property iteration isn't specified. It usually works (especially if the cloning is done the obvious way) but there's no guarantee. You really should compare based on the properties, not using JSON stringification.
You probably enter in a recursive loop, because of objects contained in customizations...
A [ customizations = B ]
B [ customizations = C ]
C [ customizations = A ]
----------------------------
Infinite loop

Categories

Resources