Reputation: 37
this is my point x=3; array =[4,8,7,5,6,9];
if would like to know if there is a value in array equal to x, and, if there isn't, find the two closest values in the left and in the right, in that case are [4,5]
I was thinking about a find for search if there is an equal value and two reduces for finding the closest smaller and, another reduce for find the closest higher but i think that there should be a better way
What is more, i need the index of the results as i have to get the value in the same position from another array. This is my code :
let prevX, nextX;
let prevY, nextY;
let xIndex = xDatas.findIndex((xData)=>{
return xPoint == xData
})
if(xIndex!=-1)
return yDatas[xIndex]
else{
prevX = xDatas.reduce(function(prev:number, curr:number) {
return (Math.abs(curr - xPoint) < Math.abs(prev - xPoint) ?curr: prev);
});
prevY = yDatas[xDatas.indexOf(prevX)];
nextX = xDatas.reduce(function(prev:number, curr:number) {
return (Math.abs(curr - xPoint) > Math.abs(prev - xPoint) ? curr : prev);
});
nextY = yDatas[xDatas.indexOf(nextX)];
Upvotes: 0
Views: 756
Reputation: 727
I think we can improve this, but this is a way:
const detectClose = (x, array) => {
// if has x, just return an array with x;
if (array.includes(x)) {
return [x];
}
// if array has less or equal 2 elements, no further verification needed
if (array.length <= 2) {
return array;
}
// function to sort array elements by its absolute distance to 'x'
const sort = (sortArray) => sortArray.sort((a, b) => {
return Math.abs(a - x) > Math.abs(b - x) ? 1 : -1;
});
// gets the numbers to the right, ordered by distance to x
const higher = sort(array.filter((i) => i > x));
// gets numbers to the left, ordered by distance to x
const lower = sort(array.filter((i) => i < x));
// no higher number? results will come from the left.
if (higher.length === 0) {
return [lower[1], lower[0]];
}
// if no lower numbers, results must come from the right
if (lower.length === 0) {
return [higher[0], higher[1]];
}
// it has numbers left or right, return the closest in each array
return [lower[0], higher[0]];
};
EDIT
You can get the index after calling the function
const x = 3;
const array = [4,8,7,5,6,9];
const items = detectClose(x, array);
const itemsIndex = items.map((i) => array.findIndex((j) => j == i));
Upvotes: 1
Reputation: 3371
The idea in the below code is to build the left and right arrays so that the two first entries in the arrays are the closest (with 0 being the very closest) on the left and right of the number respectively. They are allowed to grow larger than the two required as they are trimmed off at the end. If both left and right have values then we only need the first of each array.
I wasn't sure if you just wanted the index so I've returned both the value and the index.
const add_maybe = (arr, val, direction, obj) => {
if(arr[0] === undefined || (direction * val) > (direction * arr[0].val))
arr.unshift(obj);
else if(arr[1] === undefined || (direction * val) > (direction * arr[1].val))
arr.splice(1, 0, obj);
};
const find_closest = (x, arr) => {
if(arr.length < 3) return arr;
let left = [];
let right = [];
for(let index = 0; index < arr.length; index++) {
let val = arr[index];
let obj = { index, val };
if(val === x) return [obj];
let lt = val < x;
add_maybe(lt ? left : right, val, lt ? 1 : -1, obj);
}
if(!left.length)
return right.slice(0, 2);
if(!right.length)
return left.slice(0, 2).reverse();
return [left[0], right[0]];
};
console.log(JSON.stringify( find_closest(3, [4,8,7,5,6,9]) ));
console.log(JSON.stringify( find_closest(6, [4,8,7,5,9,10]) ));
console.log(JSON.stringify( find_closest(11, [4,8,7,5,9,10]) ));
console.log(JSON.stringify( find_closest(5, [4,8,7]) ));
console.log(JSON.stringify( find_closest(-1, [6,0,9,-2,8,-7]) ));
Upvotes: 0