I have two arrays which are
product_id = [5,5,10,15,5,15,22]
product_qty = [58,40,120,100,98,100,50]
(I have stored to array as sequence from table. id and quantity orders are same as i mentioned above.)
I want to calculate the same id's total quantity with their id. Result should be
result_id = [5,10,15,22] //no duplicates
result_qty = [196,120,200,50] //sum to same id's quantity
how to solve this issue in javascript?
One possible solution (keeping the two array solution as specified in the question, although you may want to look into a hash as specified by Vineswaran in the comments) is to traverse the first array (with the ids) and push the value if it doesn't exist in the index array, or add the value if it exists in the index array, like this:
var product_id = [5,5,10,15,5,15,22];
var product_qty = [58,40,120,100,98,100,50];
var result_id = [];
var result_qty = [];
// traverse the product ids array
$.each(product_id, function(idx, val) {
// check if that product id had a previous instance
var auxIdx = $.inArray(val, result_id)
if (auxIdx >= 0) {
// if it did, add the quantities
result_qty[auxIdx] += product_qty[idx];
} else {
// if it didn't, push both id and quantity into the result arrays
result_id.push(val);
result_qty.push(product_qty[idx]);
}
});
console.log(result_id);
console.log(result_qty);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
You can see it on this JSFiddle too: http://jsfiddle.net/pmkLcLdd/
I don't have your sample data. So, i have modified your code in the comment.
var store_product = {};
$(data).each(function(did,value){
var product_place_id = value.product_place_id_primary;
var ids = getProductAndPlaceId(product_place_id);
var item_quantity = store_product[ids[0]];
if (item_quantity) {
store_product[ids[0]] = (item_quantity + value.quantity);
} else {
store_product[ids[0]] = value.quantity;
}
});
store_product hash will have your expected result. You can convert it into array or anything as per your needs.
you don't need jquery for this
var product_id = [5,5,10,15,5,15,22]
var product_qty = [58,40,120,100,98,100,50]
var result_id = product_id.slice(); //Copy arrays
var result_qty = product_qty.slice()
var i = result_id.length;
while(i > 0){
var id = result_id.shift(); //remove first element
--i;
var sum = result_qty.shift(); //init sum count
var index = result_id.indexOf(id, 0); //find next match of element
while(index != -1){
result_id.splice(index, 1); //remove element in index
--i;
sum += result_qty.splice(index, 1)[0]; //index 0, since splice return a list with length 1
index = result_id.indexOf(id,index);
}
result_id.push(id); //add to end
result_qty.push(sum);
}
console.log(result_id);
console.log(result_qty);
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
I think an object would be better suited for what you want as a result, this way, you can easily relate an id to its quantity, with the id being the key:
var product_id = [5,5,10,15,5,15,22],
product_qty = [58,40,120,100,98,100,50],
result_qty = {};
product_qty.forEach(function (qty, i) {
var indexVal = result_qty[product_id[i]] || 0;
result_qty[product_id[i]] = indexVal + qty;
});
console.log(result_qty);
// Logs Object {5: 196, 10: 120, 15: 200, 22: 50}
console.log(result_qty[5]);
// Logs 196
//////////////////////////////////////////////////////////////////
// * However, if you really want both, the ids and quantities in
// * array format, then it's just a matter of running this,
// * after the previous code:
var tmp = [],
result_id = [];
// * (looping through the object)
for(var prop in result_qty) {
if(result_qty.hasOwnProperty(prop)) {
tmp.push(result_qty[prop]);
result_id.push(parseInt(prop, 10));
}
}
result_qty = tmp;
console.log(result_id);
// Logs [196, 120, 200, 50]
console.log(result_qty);
// Logs [5, 10, 15, 22]
I've included a way to get the arrays anyway, so you have both options.
Related
I found a lot of answers to similar questions to this, but nothing really hit the nail on the head. I need to know how to remove duplicate objects from an array but before removing them, add some of their attributes to the original object, and I need to do this with regular JavaScript, not jQuery. For example, if I run a fast food restaurant, I want to know how many burgers I sold. Every burger sold is a Food object in an array named burger like this:
burger[i] = new Food(i, name, price, tax);
I don't need to see every single whopper I sold, so I want remove from the array all but one object with a name of whopper burger[i].name but I still want to know the total I sold and tax paid, so I want to add the price and the tax. Now imagine I sell more than just burgers, so my end goal is a table that would list each individual food and it's total price and tax.
Every example I've seen to remove an object from an array seems to remove the object without a chance given to add it's individual attributes to another object first. Thanks in advance, and I apologize if this is confusing or a duplicate, but I swear I've been searching for two hours for an answer for this that works.
#RayfenWindspear #mwilson
Here is the object constructor I'm using:
//object constructor for groups
function customGroup(id, name, count, attend, tax, sold, origID) {
this.ID = id;
this.cNAME = name;
this.cCOUNT = count;
this.cATT = attend;
this.cTAX = tax;
this.cSOLD = sold;
this.cID = origID;
}//Ends function
The code creates two arrays of these objects using this code twice (I'm only putting it once here, the arrays created obviously have different names):
//loop to create objects from all groups in table
for (var i = 0; i < iName.length; i++) {
name = iName[i].innerHTML;
count = parseInt(iCount[i].innerHTML);
//count = Number(count.replace(/[^0-9\.-]+/g,""));
attend = parseInt(iAttend[i].innerHTML);
tax = iTax[i].innerHTML;
tax = Number(tax.replace(/[^0-9\.-]+/g,""));
sold = iSold[i].innerHTML;
sold = Number(sold.replace(/[^0-9\.-]+/g,""));
id = iID[i].innerHTML;
tableNames[i] = new customGroup(i, name, count, attend, tax, sold, id);
}//ends for loop
Then I compare the two tables and make an array of matching objects.
for (var i=0; i < tableNames.length; i++){
for( var j=0; j < otherTableNames.length; j++){
if (tableNames[i].cNAME == otherTableNames[j].cNAME){
count = tableNames[i].cCOUNT + otherTableNames[j].cCOUNT;
attend = tableNames[i].cATT + otherTableNames[j].cATT;
tax = tableNames[i].cTAX + otherTableNames[j].cTAX;
sold = tableNames[i].cSOLD + otherTableNames[j].cSOLD;
temp = new customGroup(j, tableNames[i].cNAME, count, attend, tax, sold, tableNames[i].cID);
namematch.push(temp);
}//ends if statement
}//ends nested loop
}//ends loop
Here is how I was trying to remove items with the same name but keep the original values.
//remove duplicate objects from namematch array
for (var i = 0, len = namematch.length; i < len; i++) {
for (var j = 0, len = namematch.length; j < len2; j++) {
if (namematch[i].cNAME === namematch[j].cNAME) {
if ( i != j){
namematch[i].cCOUNT = namematch[i].cCOUNT + namematch[j].cCOUNT;
namematch[i].cATT = namematch[i].cATT + namematch[j].cATT;
namematch[i].cTAX = namematch[i].cTAX + namematch[j].cTAX;
namematch[i].cSOLD = namematch[i].cSOLD + namematch[j].cSOLD;
namematch.splice(j, 1);
len2=namematch.length;
}//ends if statement
}//endsif statement
}//ends Nested loop
}//ends forloop
What you might want to do is, to take your burger array, .filter(fn) for burgers with the same name, and then .reduce(fn) to just a single entry.
You could use an object for grouping the single values and if necessary, you could render a single array out of it.
function Food(i, name, price, tax) {
this.i = i;
this.name = name;
this.price = price;
this.tax = tax;
}
var burger = [
new Food(0, 'Hamburger', 2, 0.4),
new Food(1, 'Cheeseburger', 2.5, 0.5),
new Food(2, 'Hamburger', 2, 0.4),
new Food(3, 'Cheeseburger', 2.5, 0.5),
new Food(4, 'Hamburger', 2, 0.4),
new Food(5, 'Cheeseburger', 2.5, 0.5),
new Food(6, 'Cheeseburger', 2.5, 0.5),
new Food(7, 'Hamburger', 2, 0.4),
],
grouped = Object.create(null),
result;
burger.forEach(function (food) {
grouped[food.name] = grouped[food.name] || { name: food.name, count: 0, price: 0, tax: 0 };
grouped[food.name].count++;
grouped[food.name].price += food.price;
grouped[food.name].tax += food.tax;
});
result = Object.keys(grouped).map(function (k) { return grouped[k]; });
console.log(grouped);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Use a Map to hold unique items and iterate the array with a for loop. Add items if they are not in the map, if already in the map add the data you want to the existing item. When done convert the maps values back to an array.
var items = [
{ type : "food1",sold : 2},
{ type : "food3",sold : 1},
{ type : "food2",sold : 3},
{ type : "food1",sold : 5},
{ type : "food3",sold : 1},
{ type : "food2",sold : 3},
{ type : "food1",sold : 5},
]
// reduce the array into a Map
var reduced = new Map();
items.forEach(item=>{ // for each item
var red = reduced.get(item.type); // get the mapped item by the item type
if(red !== undefined){ // is it defined
red.sold += item.sold; // yes add to the total
}else{
reduced.set(item.type,item); // no then add to the map
}
})
items.length = 0; // empty the old array
items.push(...reduced.values()); // add the reduced items
console.log(items); // show result
I'm new to js and have a cart in a webstore I am making for a Javascript assignment, and I can't get my total price working which displays on the webpage when the user clicks on items to add to the cart. Here is my array of items, any help would be appreciated, thank you
var cart;
var items = new Array(); //create array to store items
items[0] = "Greatest Hits CD", 10;
items[1] = "Girls CD", 10;
items[2] = "Shirt1", 20;
items[3] = "Mask Tee", 20;
items[4] = "Crewneck", 25;
items[5] = "Tour Poster", 9;
and here is my display function
this.display = function () {
this.holder.innerHTML = "";
this.totalprice = 0;
for (var i=0; i<this.quantities.length; i++) {
if (this.quantities[i] > 0) {
this.totalprice += this.quantities[i]*this.items[i];
var elm = document.createElement('div');
elm.innerHTML = "<span class='name'>"+this.items[i]+" \</span><span class='quantity'>Quantity: "+this.quantities[i]+"</span>";
this.holder.insertBefore(elm, null);
}
}
var elm = document.createElement('div');
elm.innerHTML = "<span class='price'>Total Price: $"+this.totalprice+" </span>";
this.holder.insertBefore(elm, null);
document.getElementById('quantities').value = cart.quantities;
document.getElementById('items').value = cart.items;
}
Array Reduce method is great for that, especially with the combination of Array destruct, since we only care about the price:
var items = [
["Greatest Hits CD", 10],
["Girls CD" , 10],
["Shirt1" , 20],
["Mask Tee" , 20],
["Crewneck" , 25],
["Tour Poster" , 9]
];
console.log(
items.reduce((total, [,price]) => total + price, 0)
);
You are trying to create an associative array (key/value pairs), which isn't how standard arrays work in JavaScript.
Instead, create an array of objects that store the data. Each "record" will be persisted as an object and those objects will each get a common set of property names (prop1 and prop2 in my example). You can then loop through the array of objects and upon each iteration, grab the property you are interested in (prop2) in this case.
var items = new Array(); //create array to store items
// Each item in the array will store an object with 2 properties
// Object literal syntax: {propertyName : propertyValue, propertyName : propertyValue, etc.}
items[0] = {prop1:"Greatest Hits CD", prop2:10};
items[1] = {prop1:"Girls CD", prop2:10};
items[2] = {prop1:"Shirt1", prop2:20};
items[3] = {prop1:"Mask Tee", prop2:20};
items[4] = {prop1:"Crewneck", prop2:25};
items[5] = {prop1:"Tour Poster", prop2:9};
var sum = null; // Place to store the total cost
// The JavaScript Array.prototype specifies a built-in method called
// forEach that takes a function as an argument. That function is
// automatically passed 3 arguments and is executed for each element
// in the array.
items.forEach(function(value, index, arry){
sum += value.prop2;
});
console.log(sum);
I'm trying to set select a random item from an array. Once selected, it needs to be removed from the array so it does not get selected again. Finally, once the array is emptied, the process needs to restart. I'm trying to do this using sessionStorage because I need to keep track of which random item gets selected.
// Get array from sessionStorage
myArray = JSON.parse(sessionStorage.getItem("array"));
// If array does not exist in sessionStorage, set it
if (myArray === null) {
sessionStorage.setItem("array", JSON.stringify(["apple", "orange", "banana"]));
// If array exists in sessionStorage, use it to get random item and empty it from array
} else {
var randomItem = myArray[Math.floor(Math.random() * myArray.length)];
console.log(randomItem);
console.log(myArray.splice(randomItem, 1));
}
My JSFiddle can be seen here.
Edit: Updated my work here. Eventually the array is cleared out and restarts.
This probably will not run in this sandbox (use of localstore), but I think it should work if you tried it.
// -------------------------------
// see: http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
// -------------------------------
function _shuffle (array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
// -------------------------------
// -------------------------------
// Get the next "random" item.
// -------------------------------
var randomItem = (function(allItems){
var _key = "array";
var _currentItems = [];
try {
_currentItems = JSON.parse(localStorage.getItem(_key) || "[]");
} catch (e) {
_currentItems = [];
}
if (!Array.isArray(_currentItems) || _currentItems.length === 0 ) {
console.log("resetting");
_currentItems = _shuffle(allItems.slice());
}
var _selectedItem = _currentItems.pop();
localStorage.setItem(_key, JSON.stringify(_currentItems));
return _selectedItem;
})(["apple", "orange", "banana"]);
// -------------------------------
console.log(randomItem);
A more bare bones version [ with _shuffle() from above ] might be just:
var nextItem = (function(all){
var _key = "array";
var _current = JSON.parse(localStorage.getItem(_key) || "[]");
if (_current.length === 0) { _current = _shuffle(all.slice()); }
var _selected = _current.pop();
localStorage.setItem(_key, JSON.stringify(_current));
return _selected;
})(["apple", "orange", "banana"]);
I think the problem you are having is caused by the fact that you are passing the value you get from the array the the splice() function when it is actually expecting an index. Checkout the docs page. so what you would do instead is:
// Get array from sessionStorage
myArray = JSON.parse(sessionStorage.getItem("array"));
// If array does not exist in sessionStorage, set it
if (myArray === null) {
sessionStorage.setItem("array", JSON.stringify(["apple", "orange", "banana"]));
// If array exists in sessionStorage, use it to get random item and empty it from array
} else {
//get random index of item to remove
var randomIndex = Math.floor(Math.random() * myArray.length);
//remove the item at that index
myArray.splice(randomIndex, 1); //this returns an array containing the removed item, so you can capture it if you like
}
I have an array of objects like so:
0: Object
1: Object
2: Object
3: Object
4: Object
Then when you open each object up I have some data inside like so:
id: "restore-product"
result: 0
Currently the data is output like the above but what I would love is to be able to manipulate it so i can get the returned array of objects to look like this:
[[id:"restore-product",result:0],[id:"enhance-product",result:20]]
Then when the time comes I can loop through each item and find the highest value out of the objects and get the id of that highest value.
Currently I have this function that pushes items into the array:
var amounts = [];
$.each(entries, function(i, entry){
amounts.push(entry);
});
== edit here ===
This is what i use to get the highest value:
var lowest = Number.POSITIVE_INFINITY;
var highest = Number.NEGATIVE_INFINITY;
var tmp;
for (var i=entries.length-1; i>=0; i--) {
tmp = entries[i].result;
if (tmp < lowest) lowest = tmp;
if (tmp > highest) highest = tmp;
}
console.log(highest, lowest);
Can anyone point me in the right direction?
There's a much simpler way of finding the highest value with a matching ID. Just setup two tracker variables and update them as you move through the array.
var id = null;
var localMax = Number.MIN_SAFE_INTEGER;
for (var i = 0; i < entries.length; i++) {
var obj = objects[i];
if (obj.result > localMax) {
id = obj.id;
localMax = obj.result;
}
}
The function you need is something like this:
function getIdFromMaximumResult(arr) {
var id, maxResult = Number.MIN_SAFE_INTEGER;
$.each(arr, function(i, object) {
if (object.result > maxResult) {
maxResult = object.result;
id = object.id;
}
});
return id;
}
The easiest way would be to sort the array and take either the last (ascending sort) or first (descending sort) value from the result.
Ascending sort
var sorted = yourArray.sort(function(a, b) {
return a.result < b.result ? -1 : +(a.result > b.result);
}),
highest = sorted[sorted.length - 1];
console.log(highest.id);
You could also use sorted.pop() but note that this actually removes the item from the original array too.
Descending sort
var sorted = yourArray.sort(function(a, b) {
return a.result > b.result ? -1 : +(a.result < b.result);
}),
highest = sorted[0];
console.log(highest.id);
You could also use sorted.shift() but note that this actually removes the item from the original array too.
If you need any further action, for example get all id's whose result match the highest (if any), you can now use other array methods such as filter.
var sameResult = yourArray.filter(function(data) {
return data.result === highest.result;
});
console.log(sameResult);
If you want an array containing only the id's, use map
var idOnly = sameResult.map(function(data) {
return data.id;
});
console.log(idOnly);
You can use Array.prototype.reduce()
var minMax = data.reduce(function(minMax, curr){
minMax.min = curr.result < minMax.min ? curr.result : minMax.min;
minMax.max = curr.result > minMax.max ? curr.result : minMax.max;
return minMax;
},{min:Number.POSITIVE_INFINITY, max: Number.MIN_SAFE_INTEGER} );
console.log(minMax)// {min:0, max:323}
I have a caml query which is going to return something like this in xml.
ID Title Percentage
7;#7 2 1.00000000000000
7;#7 3 0.220000000000000
7;#7 sub 1.1 0
7;#7 4 0.140000000000000
12;#12 7 0.670000000000000
13;#13 6 0.700000000000000
I'll likely create an aray of objects for each item. Something like this:
var result = [{id:7,title:"2",percent:1.0},...,{id:13,title:"6",percent:0.7}]
How could I iterate through the result and add up all the percentages with the same ID so I end up with something like:
var total = [{id:7,percent:1.36,count:4},{id:12,percent:0.67,count:1},{id:13,percent:0.7,count:1}]
Or even if I could just get
percent/count = totalPercentage so I end up with an object with just {id:7,totalPercentage:0.325}
Try this:
var percentages = {};
result.forEach(function (it) {
var obj = percentages[it.id] = percentages[it.id] || {
percent: 0,
count: 0,
id: it.id
};
obj.percent += Number(it.percent); // Casting to Number, in case percent comes as string
obj.count++;
});
This creates an object, with ids as keys. Should you wish to convert it to an array:
total = Object.keys(percentages).map(function (it) {
return percentages[it]
});
To get the average of the percentages, you can do this:
total = total.map(function(it) {
return {
id: it.id,
percent: it.percent / it.count
};
});
Just make the new object and iterate though the old one. You can see a demo here: http://jsfiddle.net/TSyE5/2/
var totalPercent = [],
total = {},
result = [{id:8,title:"3",percent:1.0},{id:7,title:"2",percent:1.0},{id:7,title:"2",percent:3.0},{id:13,title:"6",percent:0.7},{id:13,title:"6",percent:0.7},{id:13,title:"6",percent:0.7}];
$.each(result, function(){
!(this.id in total) && (total[this.id] = {id:this.id, title:this.title, percent:0, count:0});
total[this.id].percent += this.percent;
total[this.id].count++;
});
$.each(total, function(i){
total[i].percent = total[i].percent/total[i].count;
totalPercent.push({id:total[i].id, percent:total[i].percent});
});