Get the id of the nearest coordinate object - javascript

I am using the answer in the example to find the nearest object coordinate. How do I find the index of the nearest point from var points if e.g. the nearest point is {x: 12, y: 18}, then index = 1?
I want to avoid using an extra indexOf() if that step can be saved.The code is:
var points = [
{x: 10, y: 20},
{x: 12, y: 18},
{x: 20, y: 30},
{x: 5, y: 40},
{x: 100, y: 2}
];
function d(point) {
return Math.pow(point.x, 2) + Math.pow(point.y, 2);
}
var closest = points.slice(1).reduce(function(min, p) {
if (d(p) < min.d) min.point = p;
return min;
}, {point: points[0], d:d(points[0])}).point;
console.log(closest);

You could map the array to an array of objects first that also contain the index:
const points = [
{x: 10, y: 20},
{x: 12, y: 18},
{x: 20, y: 30},
{x: 5, y: 40},
{x: 100, y: 2}
];
const distance = (point) => {
return Math.pow(point.x, 2) + Math.pow(point.y, 2);
}
const result = points
.map((point, index) => ({ point, index }))
.reduce((a, b) => distance(a.point) < distance(b.point) ? a : b);
console.log(result);

Related

Is it possible to search a object in an array with both of its properties

I have the following code
const xPosition = coordinates.find(position => position.x === avoidObstacleX);
This returns me the coordinates {x: 26, y: 10} this is not wrong, but I have another coordinate that is the one I will like to output which is {x: 26, y: 11} Is there a way I can pass two parameters to the find method?
You could use two variables (not parameters to the find method itself), like you already use one:
function findObstacle(coordinates, avoidObstacleX, avoidObstacleY) {
return coordinates.find(position => position.x === avoidObstacleX
&& position.y === avoidObstacleY);
}
const xyPosition = findObstacle(coordinates, avoidObstacleX, avoidObstacleY);
But from the other answer I now learn that there are two interpretations of your question...
find only retrieves a single element, you need to use the filter method:
const coordinates = [ {x: 26, y: 10}, {x: 26, y: 11}, {x: 12, y: 34} ]
const avoidObstacleX = 26;
// returns [ {x: 26, y: 10}, {x: 26, y: 11} ]
const xPosition = coordinates.filter(position => position.x === avoidObstacleX);
To pass one value:
const coordinates= [
{x: 26, y: 10},
{x: 26, y: 11},
{x: 36, y: 6},
{x: 7,y: 8}
]
const avoidObstacleX=26;
let result = coordinates.filter(position=> {
return position.x === avoidObstacleX ;
})
console.log(result)
You can pass two values:
const coordinates= [
{x: 26, y: 11},
{x: 26, y: 11},
{x: 26, y: 11},
{x: 7,y: 8}
]
function find(avoidObstaclex,avoidObstacley){
let result= coordinates.filter(position=> {
return position.x === avoidObstaclex && position.y === avoidObstacley ;
})
return result;}
const avoidObstacleX=26;
const avoidObstacleY=11;
console.log(find(avoidObstacleX,avoidObstacleY))

How to reverse all arrays inside an object

var data = {
id: 1,
track: {
"1": [
{x: 10, y: 10},
{x: 11, y: 11},
{x: 12, y: 12}
],
"2": [
{x: 10, y: 10},
{x: 11, y: 11},
{x: 12, y: 12}
]
}
}
console.log(data.track);
var rev = data.track["1"].reverse();
console.log(rev);
How can i reverse every array inside "track" object? But I showed you above, that i am able to reverse array, by selecting it by key, but can i literally reverse every array inside "track" object?
Use Object.keys() to find all keys in your data structure
var data = {
id: 1,
track: {
"1": [
{x: 10, y: 10},
{x: 11, y: 11},
{x: 12, y: 12}
],
"2": [
{x: 10, y: 10},
{x: 11, y: 11},
{x: 12, y: 12}
]
}
}
var keys = Object.keys(data.track);
var count = keys.length;
for (var i=0;i<count;i++)
{
var rev = data.track[keys[i]].reverse();
console.log(rev);
}
It's simple. Just loop the data.track to get reverse result.
for (var i in data.track) {
console.log(data.track[i].reverse());
}

How to sum property in array of objects, based on a condition

I'm a junior Web Developer, looking for some guidance solving a problem. Please excuse me if I'm missing anything integral, as this my first time posting here.
I have an array of some data returned like so:
[
{x: Date(1234), y: 0}
{x: Date(1235), y: 0}
{x: Date(1236), y: 300}
{x: Date(1237), y: 300}
{x: Date(1238), y: 300}
{x: Date(1239), y: 300}
{x: Date(1240), y: 300}
{x: Date(1241), y: 0}
{x: Date(1242), y: 0}
{x: Date(1243), y: 0}
]
If possible, I'd like to return a new array in which all consecutive 'y' values > 0 are summed. In the new array, the summed value should be associated with the first 'x' value of the summed items, like so:
[
{x: Date(1234), y: 0}
{x: Date(1235), y: 0}
{x: Date(1236), y: 1500}
{x: Date(1241), y: 0}
{x: Date(1242), y: 0}
{x: Date(1243), y: 0}
]
I'm thinking this will likely involve 'reduce,' but I'm a little unsure how to proceed. Any help would be greatly appreciated.
Thanks in advance!
Using reduce, you could do something like this: https://jsbin.com/leladakiza/edit?js,console
var input = [
{x: Date(1234), y: 0},
{x: Date(1235), y: 0},
{x: Date(1236), y: 300},
{x: Date(1237), y: 300},
{x: Date(1238), y: 300},
{x: Date(1239), y: 300},
{x: Date(1240), y: 300},
{x: Date(1241), y: 0},
{x: Date(1242), y: 0},
{x: Date(1243), y: 0},
];
var output = input.reduce(function (acc, val) {
var lastIndex = acc.length - 1;
if (val.y <= 0 || lastIndex < 0 || acc[lastIndex].y <= 0) {
acc.push(val);
} else {
acc[lastIndex].y += val.y;
}
return acc;
}, []);
I think you can use a reduce function like this.
var arr = [{
x: Date(1234),
y: 0
},
{
x: Date(1235),
y: 0
},
{
x: Date(1236),
y: 300
},
{
x: Date(1237),
y: 300
},
{
x: Date(1238),
y: 300
},
{
x: Date(1239),
y: 300
},
{
x: Date(1240),
y: 300
},
{
x: Date(1241),
y: 0
},
{
x: Date(1242),
y: 0
},
{
x: Date(1243),
y: 0
}
];
var yGreaterThanZero = null;
var aggregated = arr.reduce(function(acc, cur) {
if (cur.y > 0) {
if (!yGreaterThanZero) {
acc.push(cur);
yGreaterThanZero = cur;
} else {
yGreaterThanZero.y += cur.y;
}
} else {
acc.push(cur);
}
return acc;
}, []);
console.log(aggregated);
This is a very crude logic. We start recording when a value greater than 0 is obtained and push it at the end of the recording (value less than 0)
var a = [
{x: Date(1234), y: 0},
{x: Date(1235), y: 0},
{x: Date(1236), y: 300},
{x: Date(1237), y: 300},
{x: Date(1238), y: 300},
{x: Date(1239), y: 300},
{x: Date(1240), y: 300},
{x: Date(1241), y: 0},
{x: Date(1242), y: 0},
{x: Date(1243), y: 0},
{x: Date(1244), y: 200},
{x: Date(1245), y: 200},
{x: Date(1246), y: 200},
{x: Date(1247), y: 200},
]
var newA = [];
var recording = false;
var temp = {}
a.forEach(item => {
if (item.y > 0) {
recording = true;
if (temp.y) {
if(!temp.x) temp.x = item.x;
temp.y = temp.y + item.y
} else {
temp = item;
}
} else {
if (recording) newA.push(temp)
recording = false;
temp = {};
newA.push(item);
}
})
if (recording) newA.push(temp)
console.log(newA)

Nesting d3.max with array of arrays

I have an array of arrays like so.
data = [
[
{x: 1, y: 40},
{x: 2, y: 43},
{x: 3, y: 12},
{x: 4, y: 60},
{x: 5, y: 63},
{x: 6, y: 23}
], [
{x: 1, y: 12},
{x: 2, y: 5},
{x: 3, y: 23},
{x: 4, y: 18},
{x: 5, y: 73},
{x: 6, y: 27}
], [
{x: 1, y: 60},
{x: 2, y: 49},
{x: 3, y: 16},
{x: 4, y: 20},
{x: 5, y: 92},
{x: 6, y: 20}
]
];
I can find the maximum y value of data with a nested d3.max() call:
d3.max(data, function(d) {
return d3.max(d, function(d) {
return d.y;
});
});
I'm struggling to understand how this code actually works. I know the second argument of the d3.max() function specifies an accessor function - but I'm confused into how exactly calling d3.max() twice relates with the accessor function.
I guess what I'm asking for is a walkthrough of how javascript interprets this code. I've walked through it on the console but it didn't help unfortunately.
Sometimes it's all about the naming of the variables:
// the outer function iterates over the outer array
// which we can think of as an array of rows
d3.max(data, function(row) {
// while the inner function iterates over the inner
// array, which we can think of as an array containing
// the columns of a single row. Sometimes also called
// a (table) cell.
return d3.max(row, function(column) {
return column.y;
});
});
You can find the source code for the d3.max function here: https://github.com/d3/d3.github.com/blob/8f6ca19c42251ec27031376ba9168f23b9546de4/d3.v3.js#L69
Wow..! intriguing question really. Just for some sporting purposes here is an ES6 resolution of this problem by invention of an array method called Array.prototype.maxByKey() So here you can see how in fact it's implemented by pure JS.
Array.prototype.maxByKey = function(k) {
var m = this.reduce((m,o,i) => o[k] > m[1] ? [i,o[k]] : m ,[0,Number.MIN_VALUE]);
return this[m[0]];
};
var data = [
[{x: 1, y: 40},{x: 2, y: 43},{x: 3, y: 12},{x: 4, y: 60},{x: 5, y: 63},{x: 6, y: 23}],
[{x: 1, y: 12},{x: 2, y: 5},{x: 3, y: 23},{x: 4, y: 18},{x: 5, y: 73},{x: 6, y: 27}],
[{x: 1, y: 60},{x: 2, y: 49},{x: 3, y: 16},{x: 4, y: 20},{x: 5, y: 92},{x: 6, y: 20}]
],
maxObj = data.map(a => a.maxByKey("y")).maxByKey("y");
console.log(maxObj);
Here is the story of what's going on in this piece of code. We will find the index of the object by reducing. Our reduce method uses an initial value, which is array [0,Number.MIN_VALUE], which at index 0 has 0 and at index 1 position has the smallest possible number in JS. Initial values are set to the first argument. So here m starts with the initial value. Reduce will walk over the array items (objects in our case) one by one and each time o will be assigned to the current object and the last argument i is of course the index of the position we are currently working on. k is provided to our function as the key that we will be using to test the max value upon.
So there is this simple ternary comparison o[k] > m[1] ? [i,o[k]] : m which means check current object property given by k (o[k]) if it is less than m[1] (where m is [0,Number.MIN_VALUE] in the first turn) return m as [i,o[k]] (check how ternaries return result) if it is not less than m[1] then return m as it is. And at the end of the walk we will be reduced down to [index of the element with max k property value, the value of that k property] in that array.
So as you see it is very simple.

From a Single JavaScriptObject to Multiple JavaScriptObjects

I have the following javaScript object
var stats = [
{x: 10, y: 300, clr:'blue'},
{x: 16, y: 600, clr:'blue'},
{x: 26, y: 300, clr:'yellow'},
{x: 36, y: 200, clr:'yellow'},
{x: 46, y: 700, clr:'green'},
{x: 56, y: 100, clr:'green'},
];
How could I able to get the following objects? Each object seperated based on clr property The main key points are to separate and append the last object of the previous object to the first object for new object.This step is required to connect lines between.
var stats1 = [
{x:10, y:300, clr:'blue'},
{x:16, y:600, clr:'blue'},
];
var stats2 = [
{x:16, y:600, clr:'yellow'},
{x:26, y:300, clr:'yellow'},
{x:36, y:200, clr:'yellow'}
];
var stats3 = [
{x:36, y:200, clr:'green'},
{x:46, y:700, clr:'green'},
{x:56, y:100, clr:'green'}
];
Another solution as you want last object to be 1st of the next array object:
var stats = [
{x: 10, y: 300, clr:'blue'},
{x: 16, y: 600, clr:'blue'},
{x: 26, y: 300, clr:'yellow'},
{x: 36, y: 200, clr:'yellow'},
{x: 46, y: 700, clr:'green'},
{x: 56, y: 100, clr:'green'},
];
function groupBy( array ,prop, f )
{
var groups = {};
///grouping & sorting
array.forEach( function( o )
{
var group = JSON.stringify( f(o) );
groups[group] = groups[group] || [];
groups[group].push( o );
});
var last_prop = "" ;
var last_elm = {} ;
for(var key in groups )
{
if(last_prop !== "")
{
last_elm[prop] = groups[key][0][prop] ;
groups[key].unshift(last_elm);
}
last_prop = key;
last_elm = (JSON.parse(JSON.stringify(groups[key][groups[key].length - 1])));
}
return Object.keys(groups).map( function( group )
{
return groups[group];
});
}
var result = groupBy(stats, "clr", function(item)
{
return [item.clr];
});
console.log(result);
document.write(JSON.stringify(result));
if it doesn't work try jsbin version http://jsbin.com/tudahibefo/1/
var stats = [
{x: 10, y: 300, clr:'blue'},
{x: 16, y: 600, clr:'blue'},
{x: 26, y: 300, clr:'yellow'},
{x: 36, y: 200, clr:'yellow'},
{x: 46, y: 700, clr:'green'},
{x: 56, y: 100, clr:'green'},
];
var stats1 = []; // blue
var stats2 = []; // yellow
var stats3 = []; // green
var last_item = null;
for (var i = 0; i < stats.length; i++) {
var cur_item = stats[i];
switch (cur_item.clr) {
case "blue":
target = stats1;
break;
case "yellow":
target = stats2;
break;
case "green":
target = stats3;
break;
}
if (last_item && last_item.clr != cur_item.clr) {
// Push last item of previous colow onto new color
target.push({
x: last_item.x,
y: last_item.y,
clr: cur_item.clr
});
}
target.push(cur_item);
last_item = cur_item;
}
document.getElementById("output").innerHTML = JSON.stringify(stats1) + "<br>" + JSON.stringify(stats2) + "<br>" + JSON.stringify(stats3);
<div id="output"></div>
Use filter to obtain three separate arrays:
stats1 = stats.filter(function(x){return x.clr=="blue"});
stats2 = stats.filter(function(x){return x.clr=="yellow"});
stats3 = stats.filter(function(x){return x.clr=="green"});
then add the last element of the previous array to the next one with splice
stats2.splice(0,0,stats1[stats1.length-1]);
stats3.splice(0,0,stats2[stats2.length-1]);
then change the color of the first element of arrays stats2 and stats3
stats2[0].clr="yellow";
stats3[0].clr="green";
UPDATE: I've updated the solution to have the ability to connect last elements to form a link
I present a generic solution that allows you to split the array irrespective of which colors are part of the stats array.
var stats = [
{x: 10, y: 300, clr:'blue'},
{x: 16, y: 600, clr:'blue'},
{x: 26, y: 300, clr:'yellow'},
{x: 36, y: 200, clr:'yellow'},
{x: 46, y: 700, clr:'green'},
{x: 56, y: 100, clr:'green'},
];
// the function receives the property with which you want to divide
// in our case, it is the 'clr' property
// the 'connectLast' boolean flag is used to connect the last link
var divideArrayByProperty = function(arr, property, connectLast) {
var dividedArrays = {};
var key = null;
var lastElement = null;
for (var i = 0; i < arr.length; i++) {
key = arr[i][property];
if (undefined === dividedArrays[key]) {
dividedArrays[key] = [];
if (connectLast === true && i > 0) {
lastElement = JSON.parse(JSON.stringify(arr[i-1]));
lastElement.clr = key;
dividedArrays[key].push(lastElement);
}
}
dividedArrays[key].push(arr[i]);
}
return dividedArrays;
};
var result = divideArrayByProperty(stats, 'clr', true);
document.getElementById("output").innerHTML = JSON.stringify(result);
<div id='output'></div>
Yet another solution.
var stats = [
{x: 10, y: 300, clr:'blue'},
{x: 16, y: 600, clr:'blue'},
{x: 26, y: 300, clr:'yellow'},
{x: 36, y: 200, clr:'yellow'},
{x: 46, y: 700, clr:'green'},
{x: 56, y: 100, clr:'green'},
];
function groupWith(arr, f) {
var result = [], group = [];
arr.forEach(function(elem) {
if(group.length !== 0 && !f(group[group.length - 1], elem)) {
result.push(group);
group = [];
}
group.push(elem);
});
result.push(group);
return result;
}
function getLast(array) {
return array[array.length - 1];
}
function copyObject(obj) {
return JSON.parse(JSON.stringify(obj));
}
var statsGrouped = groupWith(stats, function(a, b) {return a.clr === b.clr});
for(var i = 1; i < statsGrouped.length; i++) {
statsGrouped[i].unshift(copyObject(getLast(statsGrouped[i-1])));
statsGrouped[i][0].clr = statsGrouped[i][1].clr;
}
console.log(statsGrouped);

Categories

Resources