How to get index of the array item with nearest value? - javascript

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

Related

Javascript - Get occurence of json array with ESLINT 6

I can't set up an algo that counts my occurrences while respecting ESlint's 6 standards in javascript.
My input table is :
[
{
"id": 2,
"name": "Health",
"color": "0190fe"
},
{
"id": 3,
"name": "Agriculture",
"color": "0190fe"
},
{
"id": 1,
"name": "Urban planning",
"color": "0190fe"
},
{
"id": 1,
"name": "Urban planning",
"color": "0190fe"
}
]
And i want to get :
{"Urban planning": 2, "Health": 1, ...}
But that does not work with ESLINT / REACT compilation...
This is my code :
const jsonToIterate = *'MyPreviousInputJson'*
const names = []
jsonToIterate.map(item => (names.push(item.name)))
const count = []
names.forEach(item => {
if (count[item]){
count.push({text: item, value: 1})
} else {
count.forEach(function(top){top.text === item ? top.value =+ 1 : null})
}
})
Thank you so much
Well, you want an object in the end, not an array, so count should be {}. I also wouldn't use map if you're not actually returning anything from the call. You can use reduce for this:
let counts = topicsSort.reduce((p, c, i, a) => {
if (!p.hasOwnProperty(c.name)) p[c.name] = 0;
p[c.name]++;
return p;
}, {});
I'm half exppecting someone to close this as a duplicate because all you've asked for is a frequency counter. But here's an answer anyway:
const jsonToIterate = *'MyPreviousInputJson'*;
const names = {};
jsonToIterate.map(obj => {
if(obj.name in names){
names[obj.name]++
}
else{
names[obj.name] = 1;
}
})

Looping between functions and storing results

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.

Evaluating key values in multi-dimensional object

I have a multi-dimensional object that looks like this:
{
"links": [{"source":"58","target":"john","total":"95"},
{"source":"60","target":"mark","total":"80"}],
"nodes":
[{"name":"john"}, {"name":"mark"}, {"name":"rose"}]
}
I am trying to evaluate the value of "total" in "links." I can do this in a one-dimensional array, like this:
for (var i = 0; i < data.length; i++) {
for (var key in data[i]) {
if (!isNaN(data[i][key])) {
data[i][key] = +data[i][key];
}
}
};
But I have not been able to figure out how to do this in two-dimensions (especially calling the value of key "total" by name).
Can anybody set me on the right track? Thank you!
Starting from the principle that the structure of your array is this, you can to iterate the keys and the values:
var obj = {
"links": [{"source":"58","target":"john","total":"95"},
{"source":"60","target":"mark","total":"80"}],
"nodes":
[{"name":"john"}, {"name":"mark"}, {"name":"rose"}]
};
for (var key in obj){
obj[key].forEach(function(item){
for(var subkey in item){
if (subkey == 'total')
console.log(item[subkey]);
};
});
};
You can get total using reduce
check this snippet
var obj = {
"links": [{
"source": "58",
"target": "john",
"total": "95"
}, {
"source": "60",
"target": "mark",
"total": "80"
}, {
"source": "60",
"target": "mark",
"total": "80"
}],
"nodes": [{
"name": "john"
}, {
"name": "mark"
}, {
"name": "rose"
}]
}
var links = obj.links;
var sum = links.map(el => el.total).reduce(function(prev, curr) {
return parseInt(prev, 10) + parseInt(curr, 10);
});
console.log(sum);
Hope it helps
Extract the values from the array, convert them to numbers and add them up.
Array.prototype.map() and Array.prototype.reduce() are pretty helpful here:
var data = {"links":[{"source":"58","target":"john","total":"95"},{"source":"60","target":"mark","total":"80"}], "nodes":[{"name":"john"}, {"name":"mark"}, {"name":"rose"}]};
var sum = data.links.map(function(link) {
return +link.total;
}).reduce(function(a, b) {
return a + b;
});
console.log(sum);

reset object order javascript

I have a object like this
{
"items":{
"2":{
"id":122,
"product_id":"DE",
"price":"9.35",
},
"4":{
"id":15,
"product_id":"CH",
"price":"8.00",
}
"7":{
"id":78,
"product_id":"CH",
"price":"3.00",
}
},
"total_price":"20.35",
"item_count":2,
"unit":"CHF"
}
Do you know how i reset the items order.
now 2, 4, 7
should be 0, 1, 2
Created a JSfiddle that shows you a way.
Im using a custom format function:
function format(object) {
var items = {};
var i = 0;
for (var index in object.items) {
items[i] = object.items[index];
i++;
}
object.items = items;
}
The resulted object is this:
{
"items": {
"0": {
"id": 122,
"product_id": "DE",
"price": "9.35"
},
"1": {
"id": 15,
"product_id": "CH",
"price": "8.00"
},
"2": {
"id": 78,
"product_id": "CH",
"price": "3.00"
}
},
"total_price": "20.35",
"item_count": 2,
"unit": "CHF"
}
How about this
var obj = {
"items":{
"2":{
"id":122,
"product_id":"DE",
"price":"9.35",
},
"4":{
"id":15,
"product_id":"CH",
"price":"8.00",
},
"7":{
"id":78,
"product_id":"CH",
"price":"3.00",
}
},
"total_price":"20.35",
"item_count":2,
"unit":"CHF"
}
var keys = Object.keys(obj.items)
for (var i = 0; i < keys.length; i++) {
obj.items[i] = obj.items[keys[i]];
delete obj.items[keys[i]];
};
console.log(obj);
Object properties do not have order. I assume you want to re-name the properties, counting up from 0, but have the properties maintain the original relative ordering of their keys. (So the property with the smallest name is renamed to 0, the second-to-smallest is 1, etc.)
To do this, get all the property names, and sort the names numerically. Then, get all the values in the same over as their sorted property names. Finally, re-insert those property values with their new property names.
var itemsObj = obj["items"];
// get all names
var propertyNames = Object.keys(itemsObj);
// sort property names in numeric order: ["2", "4", "7"]
propertyNames.sort(function(a,b){ return a-b; });
// get property values, sorted by their property names
// ["2", "4", "7"] becomes [{ "id":122, .. }, { "id":15, ... }, { "id":78, ... }]
var values = propertyNames.map(function(propName) { return itemsObj[propName]; }
// clear out old property and add new property
for(var i=0; i<values.length; ++i) {
delete itemsObj[propertyNames[i]];
itemsObj[i] = values[i];
}
var data = {
"items": {
"2": {
"id": 122,
"product_id": "DE",
"price": "9.35",
},
"4": {
"id": 15,
"product_id": "CH",
"price": "8.00",
},
"7": {
"id": 78,
"product_id": "CH",
"price": "3.00",
}
},
"total_price": "20.35",
"item_count": 2,
"unit": "CHF"
};
var indices = Object.keys(data.items).map(function(i) { return parseInt(i, 10); }),
counter = 0;
indices.sort();
indices.forEach(function (i) {
if (i > counter) { // put here some more collision detecting!
data.items[counter] = data.items[i];
delete data.items[i];
counter++;
}
});
Object properties order is not guaranteed anyway. You should use an array instead.
Take a look at this answer

reduce array of objects: limit similar fields based on value from another field

I need a fast way to perform this. It has to be fast.
In the array, the objects are sorted by score already. I want to make a new array with the top 2 scored objects for any given rootTerm.
Here is the original.
"results": [
{
"score": 100,
"source": {
"term": "bovine1",
"rootTerm": "cow",
}
},
{
"score": 50,
"source": {
"term": "bovine2",
"rootTerm": "cow",
}
},
{
"score": 10,
"source": {
"term": "bovine3",
"rootTerm": "cow",
}
},
{
"score": 10,
"source": {
"term": "scrofa",
"rootTerm": "pig",
}
]
Bovine3 is not in the top 2 highest scored objects for rootTerm cow, so I want it removed.
The new result would be
"results": [
{
"score": 100,
"source": {
"term": "bovine1",
"rootTerm": "cow",
}
},
{
"score": 50,
"source": {
"term": "bovine2",
"rootTerm": "cow",
}
},
{
"score": 10,
"source": {
"term": "scrofa",
"rootTerm": "pig",
}
]
You can filter it in place using Array.filter(), but you do need to track the rootTerms as you see them, keeping count as you go along.
var tracker = {};
data.filter(function(value, index, array) {
var rootTerm = value.source.rootTerm;
if (undefined === tracker[rootTerm])
{
tracker[rootTerm] = 0;
}
tracker[rootTerm] += 1;
return (tracker[rootTerm] <= 2)
});
Make another array, with keys cow, pig, etc. and set values to 0. Iterate the original array and increase the value in second array every time you pass through entity with given key. Delete the entity if the value is 2 or more.
Example:
var counter = [pig: 0, cow: 0];
foreach(var key in originalArray) {
if(++counter[originalArray[key].source.rootTerm] >= 2) {
// remove somehow the item (maybe using array.splice() )... its on you
}
}

Categories

Resources