I would like produce a list of grouped JSON elements according to a specific criteria, but I am unable to make my loop work.
The function should make groups of with 12 bottles and return a single JSON list. So in this example, the function should extract the 3 first items and then run again to extract the remaining ones. But I am looping forever... Thank you in advance,
var data = {
"order": [
{ "product": "MAXIMUS", "quantity": "3" },
{ "product": "COLECCION", "quantity": "3" },
{ "product": "CABERNET FRANC", "quantity": "6" },
{ "product": "CHARDONNAY", "quantity": "6" },
{ "product": "SAUVIGNON BLANC", "quantity": "6" }
]
};
var qtd = data.order;
var size = qtd.length;
var addline = '';
var add = '';
var total = 0;
var i = 0;
var a = 0;
var c = '';
function MakeList(i, add) {
for (i < 0; total < 12; i++) {
total += parseInt(qtd[i].quantity);
addline = addline + '{' + '"quantity": "' + qtd[i].quantity + ' units"},';
i = i++;
add = '{"Box of 12":[' + addline.slice(0, -1) + "]}";
}
return [i, add];
}
function BuildLabels(i, add) {
for (i < 0; c = "true"; i++) {
c = a[0] < size;
a += MakeList(i, add);
i = i++;
}
return a;
}
var results = BuildLabels(i, add);
output = { id: 3, results };
for (i < 0; c = "true"; i++)
something weird is happening here. You don't set any condition on cycle to stop, you just assign value "true" to c. Try to use == instead of =; also initialization looks strange - set i to 0. Apparently, It will make the whole thing work (at least the loop will stop at some point), but in the end I get that the variable results is equal to 0. There are other mistakes/weird stuff out there. Propably, you wanted to achieve something like this:
var data = {
"order": [
{ "product": "MAXIMUS", "quantity": "3" },
{ "product": "COLECCION", "quantity": "3" },
{ "product": "CABERNET FRANC", "quantity": "6" },
{ "product": "CHARDONNAY", "quantity": "6" },
{ "product": "SAUVIGNON BLANC", "quantity": "6" }
]
};
function MakeList(data) {
var selected = [], bottlesNum = 0;
for (var i = 0; bottlesNum < 12; i++) {
selected.push(data.order[i]);
bottlesNum += parseInt(data.order[i].quantity);
}
return selected;
}
var results = MakeList(data);
// now it is a JS object:
console.log({ id: 3, results: results });
// if you want it to be a JSON string, use JSON.stringify():
console.log(JSON.stringify({ id: 3, results: results }));
check it out.
UPDATE
var data = {
"order": [
{ "product": "MAXIMUS", "quantity": "3" },
{ "product": "COLECCION", "quantity": "3" },
{ "product": "CABERNET FRANC", "quantity": "6" },
{ "product": "CHARDONNAY", "quantity": "6" },
{ "product": "SAUVIGNON BLANC", "quantity": "6" }
]
};
function makeGroup(data, max) {
var selected = [], bottlesNum = 0;
while(data.order.length) {
if(bottlesNum + +data.order[0].quantity > max) break;
var order = data.order.shift();
bottlesNum += +order.quantity; // casting to Number
selected.push(order);
}
return selected;
}
function splitOrder(data, max) {
while(data.order.length) {
var results = makeGroup(data, max);
if(!results.length) {
console.log("Error: a product's quantity is greater than max. size of the group. Try to increase max. size of the group.");
break;
}
console.log({ results: results });
}
}
// 2nd argument - max. size of the group. In case of 12 there will be 2 groups - of 3, 3, 6 and 6, 6 bottles
splitOrder(data, 12);
// Also notice that if max. size of the group is a changing value and can be set somehow to, lets say, 4 which is fewer than number of some products (6) in our order. So, it is impossible to complete such a task without taking some additional steps to handle this situation. For example, we could filter our data beforehand to exclude products with numbars greater than 4 and then form groups based on the rest of the data. Or we can treat products with number equal to 6 as if they satisfy our constraint etc.
Related
i know it is a repeated Question but i can't figure the proper way to add an object to an array with checking if there is match or not like , this is a function that loops through an array of words and check if the entered word is in the array so increase its count by 1 , if not push this word to the array
and set its count by 0
function addWord(request, response) {
var data = request.params;
var word = data.word;
var reply;
for (i = 0; i < Words.length; i++){
if (Words[i].type != word){
reply = {
msg: "not Found but added"
};
Words.push({"type": word , "count": 0});
} else if (Words[i].type == word) {
reply = {
msg: "already Found and added"
};
Words.count++;
}
}
var x = JSON.stringify(Words, null, 2);
fs.writeFile('count.json', x, finished);
function finished(){
console.log('Yay')
}
the problem is the output gives me four new elements not just one and with Count 1 not 0, lets say that i added the word Music the output is like so
[
{
"type": "physical",
"count": 8
},
{
"type": "WCAP",
"count": 2
},
{
"type": "BLQ",
"count": 2
},
{
"type": "unable",
"count": 2
},
{
"type": "music",
"count": 1
},
{
"type": "music",
"count": 1
},
{
"type": "music",
"count": 1
},
{
"type": "music",
"count": 1
},
]
The problem is that you first must loop over all the words before deciding if a word is in the list or not. You could fix your code to look like this:
var found = false
for (i = 0; i < Words.length; i++){
if (Words[i].type == word){
Words[i].count++
reply = {
msg: "already Found and added"
};
found = true;
break;
}
}
if (!found) {
Words.push({"type": word , "count": 0});
reply = {
msg: "already Found and added"
};
}
And just in case, here is a snippet with a simpler addWord function that might help you:
var Words = [];
function addWord(word) {
for (var i=0; i < Words.length; i++) {
if (word == Words[i].type) {
Words[i].count++
return
}
}
Words.push({type: word, count: 0})
}
addWord('stack')
addWord('overflow')
addWord('stack')
console.log(Words)
try the following function:
function findWord(Words) {
let found = Words.some(word => word.type == yourWord)
return found;
}
for (var i = 0; i < itemArray.length; i++) {
//console.log(itemArray[index].mats);
var newMatArray = [];
for (var j = 0; j < itemArray[i].mats.length; j++) {
var mat = itemArray[i].mats[j];
if (isInNewArray(mat.id, newMatArray)) {
continue;
}
for (var k = 0; k < itemArray[i].mats.length; k++) {
var mat2 = itemArray[i].mats[k];
if (k == j) {
continue;
}
if (mat.id == mat2.id) {
//if (itemArray[i].id == 12005) console.log("adding " + mat.quantity + " of " + mat.name + " to " + mat2.quantity);
mat.quantity = mat.quantity + mat2.quantity;
}
}
newMatArray.push(mat);
}
//if (itemArray[i].id == 12005) console.log(newMatArray);
itemArray[i].mats = newMatArray;
}
function isInNewArray(id, array) {
for (var i = 0; i < array.length; i++) {
if (array[i].id == id) {
return true;
}
}
return false;
}
So this loop is supposed to iterate over an array of items and remove/combine duplicate mats required for an item, each item is a json object with a name/id and a mats array of objects and each mat has a name/id/quantity required. For some reason if i iterate over only 1 item at some point in the array then continue on all the rest without combining it works totally fine.
It's only when its looping that changing the values of previous objects seems to change the value of future objects resulting in mats hitting quantities of 1.17555e^105 which is way higher than they should be. Does javascript do some kind of memory optimization that might be storing mat objects with identical values to the same location so when i increase the quantity on objects earlier in the loop it does so for objects later in the loop? Otherwise I don't understand why this algorithim works for 1 off objects but looping over objects and only ever changing one object at a time messes it up.
Edit: sample object below
{
"id": 622,
"bpid": 692,
"quantity": 1,
"name": "Stabber",
"mats": [
{
"id": 34,
"name": "Tritanium",
"quantity": 48518335
},
{
"id": 35,
"name": "Pyerite",
"quantity": 11828791
},
{
"id": 36,
"name": "Mexallon",
"quantity": 40000
},
{
"id": 37,
"name": "Isogen",
"quantity": 10333
},
{
"id": 38,
"name": "Nocxium",
"quantity": 2778
},
{
"id": 39,
"name": "Zydrine",
"quantity": 1244
},
{
"id": 40,
"name": "Megacyte",
"quantity": 244
},
{
"id": 20411,
"name": "Datacore - High Energy Physics",
"quantity": 8
},
{
"id": 20172,
"name": "Datacore - Minmatar Starship Engineering",
"quantity": 8
}
]
}
for (var i = 0; i < matsArray.length; i++) {
var item = matsArray[i];
var type = parseInt(item.typeID, 10);
var index = findItemIndex(type);
if (index > -1) {
var mat = {
id: parseInt(item.materialTypeID, 10),
name: itemIDMap.get(parseInt(item.materialTypeID, 10)),
quantity: parseInt(item.quantity, 10)
}
itemArray[index].mats.push(mat);
} else {
if (bpMap.get(parseInt(item.typeID, 10)) == undefined) {
//console.log(item);
continue;
}
var newItem = {
id: bpMap.get(parseInt(item.typeID, 10)).itemID,
bpid: parseInt(item.typeID, 10),
quantity: bpMap.get(parseInt(item.typeID, 10)).quantityPerRun,
name: itemIDMap.get(bpMap.get(parseInt(item.typeID, 10)).itemID),
mats: []
}
var mat = {
id: parseInt(item.materialTypeID, 10),
name: itemIDMap.get(parseInt(item.materialTypeID, 10)),
quantity: parseInt(item.quantity, 10)
}
newItem.mats.push(mat);
itemArray.push(newItem);
productsArray.push(newItem.id);
}
}
Would this array creation code create identical mat objects? Shouldn't each newly created mat be a separate object?
I am receiving real-time responses from the back-end that contains the following JSON (almost every second):
One Array:
{
"newUpdate": [
{
"id": "TP",
"val" : 3
},
{
"id": "TPE20",
"val" : 3
}]
}
Another array (after one second or less)
{
"newUpdate": [
{
"id": "CRK",
"val" : 24
},
{
"id": "TPE20",
"val" : 44
}]
}
I am getting the above JSON almost every second knowing that each time it comes with different values and id's, and the array itself does not have a specific size.
Well, what I want to do is to get the average of the values having the same key 'id'.
For example, for the above array, the average will be for TPE20 :
(3+44)/2 =23.2 (as it computes the average for the id : TPE20)
Then it should show it here (using JQuery for example) [Think of the real-time average value like in the stock market]
<div id="TPE20"></div>
Currently, using the below for loop, I print the JSON listed above:
for(var i in load.updates){
var id = load.newUpdate[i].id;
updatesMap[id] = load.newUpdate[i].value;
var valueOfID = newUpdate[id];
}
The challenge is that I am receiving a lot of arrays at once (1/sec), each array contains different "id" and "val", I really don't know how I can compute the average using the way I described above!
Just use an object with keys representing the ids of the array objects and the values as objects containing the count, total, and average of those ids.
When you receive a new array simply update the object:
function updateObj(arr) {
arr.forEach(function(el) {
var key = el.id;
obj[key] = obj[key] || { count: 0, total: 0, avg: 0 };
obj[key].count++;
obj[key].total += el.val;
obj[key].avg = obj[key].total / obj[key].count;
});
}
Here's a simulation with setInterval sending one array to the function each second, and then displaying the completed object in the console.
Does this help? It get the Average of the search term like you asked. It uses jquery $.each to iterate through the array
var newdata = [
{
"newUpdate": [
{
"id": "TP",
"val" : 3
},
{
"id": "TPE20",
"val" : 3
}]
},
{
"newUpdate": [
{
"id": "CRK",
"val" : 24
},
{
"id": "TPE20",
"val" : 44
}]
}
]
function getAverage(array, term){
var sum = 0, n = 0;
$.each(array, function(i, item){
n++
var arrs = item.newUpdate
$.each(arrs, function(d, place){
// console.log(d)
if (place.id == term){
sum +=place.val
}
})
})
return sum / n
}
document.write(getAverage(newdata, "TPE20"))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
You can use Array.prototype.forEach() , create a private property at an object to store number of occasions unique property occurs within callback; pass each object individually to function in succession to maintain averages of properties at single object
var a = {
"newUpdate": [{
"id": "TP",
"val": 3
}, {
"id": "TPE20",
"val": 3
}]
};
var b = {
"newUpdate": [{
"id": "CRK",
"val": 24
}, {
"id": "TPE20",
"val": 44
}]
}
var avg = {};
function update(update) {
update.newUpdate.forEach(function(value, index) {
if (!avg[value.id] || !avg.hasOwnProperty(value.id)) {
avg["_" + value.id] = 1;
avg[value.id] = value.val / avg["_" + value.id];
} else {
++avg["_" + value.id];
avg[value.id] += value.val;
avg[value.id] = avg[value.id] / avg["_" + value.id];
}
});
return avg
}
console.log(update(a), update(b), avg)
I currently have a complex orders array (coming from a JSON client) that contains multiple orders like this (contains 2):
0: {
"employee": "Nicole"
"total": 13
"lineItems": {
"elements": [2]
0: {
"name": "Burger"
"price": 8
}
1: {
"name": "Lamb"
"price": 6.50
}
}
}
1: {
"employee": "Dan"
"total": 11
"lineItems": {
"elements": [2]
0: {
"name": "Lamb"
"price": 4.50
}
1: {
"name": "Meatballs"
"price": 6.50
}
}
}
What I want to do is create a new array that loops through the above and creates new items array based on the name of the lineItems object above. i.e. final output looks something like this:
var items = {
"Burger" = {
"totalSpent" : 8
},
"Lamb" = {
"totalSpent" : 13
// Note this totalSpent is an iteration or sum of all "price" items where name/id = "Lamb"
},
"Meatballs" = {
"totalSpent" : 4.50
}
}
I'm more used to PHP and have tried a number of different versions of this but can't seem to get the desired output. Here's what I've got so far:
var orders = //As above//
// Initialising new array to hold my final values
var orderItems = [];
for (var i = 0, len = orders.length; i < len; i++){
for(var e = 0, leng = orders[i]['lineItems']['elements'].length; e < leng; e++){
var totalSpent = 0;
var id = orders[i]['lineItems']['elements'][e]['name'];
if (orders[id] in orderItems[id]){
// overwrite existing array item
orderItems[id]['totalSpent'] += orders[i]['lineItems']['elements'][e]['price'];
orderItems[id].push({totalSpent : orderItems[id]['totalSpent']});
}
else {
// Create new array item
orderItems.push(id);
orderItems[id].push({totalSpent : orders[i]['lineItems']['elements'][e]['price']});
}
}
}
Edit:
Had to correct your orders syntax, I added it to my answer so you can run the Javascript Snippet;
Changed the whole dot notation to bracket notation to make it easier to read and understand;
Corrected the bug about items remaining an empty array (it was in the inner for);
var orders = [
{
"employee": "Nicole",
"total": 13,
"lineItems": {
"elements": [
{
"name": "Burger",
"price": 8
},
{
"name": "Lamb",
"price": 6.50
}
]
}
},
{
"employee": "Dan",
"total": 11,
"lineItems": {
"elements": [
{
"name": "Lamb",
"price": 4.50
},
{
"name": "Meatballs",
"price": 6.50
}
]
}
}
];
var items = {};
// loop in orders array
for (var i = 0; i < orders.length; i++) {
var elements = orders[i]["lineItems"]["elements"];
// loop in orders[i]["lineItems"]["elements"] object
for (var eIndex in orders[i]["lineItems"]["elements"]) {
// Add new item if it doesn't already exist
if (!items.hasOwnProperty(elements[eIndex]["name"])) {
items[elements[eIndex]["name"]] = {"totalSpent": elements[eIndex]["price"]};
} else {
// If it exists, sum totalSpent
items[elements[eIndex]["name"]]["totalSpent"] += elements[eIndex]["price"];
}
}
}
console.log(items);
PS: To find out why I'm using bracket notation instead of dot notation, check this question, it's good to know!
First of all, there are some error in your order array, note the difference between {} (for objects) and []. Then it is just simple use of the map function to iterate over the arrays.
See your browser console (F12) for the result of this snippet
var orders = [{
"employee": "Nicole",
"total": 13,
"lineItems": {
"elements": [{
"name": "Burger",
"price": 8
}, {
"name": "Lamb",
"price": 6.50
}
]
}
}, {
"employee": "Dan",
"total": 11,
"lineItems": {
"elements": [{
"name": "Lamb",
"price": 6.50
}, {
"name": "Meatballs",
"price": 4.50
}]
}
}]
var items = {}
orders.map(function(order) {
order.lineItems.elements.map(function(elem) {
if (items[elem.name]) {
items[elem.name].totalSpent += elem.price
} else {
items[elem.name] = {"totalSpent": elem.price}
}
})
})
console.log(items)
I have following array of the objects in json and i would like to get index of the object in array which is nearest by count of days attribute opposite the given number value.
Exist any built-in function in jQuery or JS for this, or how can i easily solve it please?
Thanks for any help.
"warningAttributes": [
{
"id": "3",
"days": 15,
"color": "#FFFFFF"
},
{
"id": "4",
"days": 98,
"color": "#343434"
}
]
var warningAttributes = [{"id": "3", "days": 15, "color": "#FFFFFF"},
{"id": "4", "days": 98, "color": "#343434"}]
var target = 90;
var nearest = warningAttributes.sort(function(a,b){
return Math.abs(a.days-target) - Math.abs(b.days-target)
})[0];
This also gives you the list of the nearest, if you leave off [0]
Considering you are trying to find the ID which is closest.
you can do this, http://jsfiddle.net/s4jq5kv7/ . though you will need to clean the code, but this works.
var id=3;
var temp;
var prev;
var x={"warningAttributes": [
{
"id": "3",
"days": 15,
"color": "#FFFFFF"
},
{
"id": "4",
"days": 98,
"color": "#343434"
}
]
}
prev=x.warningAttributes[0].id;
val=prev;
$(x.warningAttributes).each(function(i,ele){
if(id>parseInt(ele.id)){
temp=id-parseInt(ele.id);
}else{
temp=parseInt(ele.id)-id;
}
if(prev>temp)
{prev=temp;
val=ele.id;}
})
console.log(val)
The only problem would be, if there is a number which has same difference with more than two numbers, in that case the first one is returned.
Ex 3 and 4, and if you find nearest to 3.5, you get the first number i.e 3.
If I uderstand well:
jQuery(document).ready(function () {
var control=40;
var json = {"warningAttributes": [
{
"id": "3",
"days": 15,
"color": "#FFFFFF"
},
{
"id": "4",
"days": 98,
"color": "#343434"
},
{
"id": "5",
"days": 40,
"color": "#343434"
}
]};
$.each(json.warningAttributes, function(k, v) {
var diff;
diff= control - v.days
if(diff==0) alert("this is your element: " + v.id);
})
});
As easy as this:
function getNearest(arr,value)
{
var diff = null;
var index= 0;
$.each(arr,function(i,item) {
var current = Math.abs(item.days - value);
if (diff == null) diff = current;
if (current< diff)
index=i;
});
return index
}
Here's my go because writing short code is fun.
var warningAttributes = [{"id": "3", "days": 15, "color": "#FFFFFF"},
{"id": "4", "days": 98, "color": "#343434"}]
var n = 90;
var distances = warningAttributes.map(function(c) {return Math.abs(n - c.days);})
var nearest_idx = distances.indexOf(Math.min.apply(Math, distances));
Chris has pretty much stolen this (+1), but here's a breakdown of how I attempted it:
function getDays(arr, value) {
// get a list of the differences between the requested value
// and the numbers in the array and make them all positive
var abs = arr.map(function (el) { return Math.abs(el.days - value); });
// find the smallest number
var smallest = Math.min.apply(null, abs);
// find out where that number is in the positive number array
var index = abs.indexOf(smallest);
// return an object that contains the index of the
// object, and the number of days that were closest
return { index: index, value: arr[index].days };
}
var result = getDays(arr, 35); // Object { index: 3, value: 17 }
Get the index with result.index.
DEMO