我正在研究一种小型算法,用于在随机数字数组中找到给定数字的最接近值。在我的情况下,我试图检测由6位数字ID(“ 123456”,“ 0078965”,...)标识的已连接计算机,但是它对于例如找到我附近最接近地理位置的用户很有用。 >
我需要列出5个最接近的计算机,而不管它们的ID是高还是低。这段代码可以完美地运行,但是我正在寻找一种更聪明,更好的方式进行处理,我要处理很多循环和数组。
let n = 0; // counter
let m = 5; // number of final machines to find
// list of IDs founded (unordered: we can't decide)
const arr = ["087965","258369","885974","0078965","457896","998120","698745","399710","357984","698745","789456"]
let NUM = "176789" // the random NUM to test
const temp = [];
const diff = {};
let result = null;
// list the [m] highest founded (5 IDs)
for(i=0 ; i<arr.length; i++) {
if(arr[i] > NUM) {
for(j=0 ; j<m; j++) {
temp.push(arr[i+j]);
} break;
}
}
// list the [m] lowest founded (5 IDs)
for(i=arr.length ; i>=0; i--) {
if(arr[i] < NUM) {
for(j=m ; j>=0; j--) {
temp.push(arr[i-j]);
} break;
}
}
// now we are certain to get at least 5 IDs even if NUM is 999999 or 000000
temp.sort(function(a, b){return a - b}); // increase order
for(i=0 ; i<(m*2); i++) {
let difference = Math.abs(NUM - temp[i]);
diff[difference] = temp[i]; // [ 20519 : "964223" ]
}
// we now get a 10-values "temp" array ordered by difference
// list the [m] first IDs:
for(key in diff){
if(n < m){
let add = 6-diff[key].toString().length;
let zer = '0'.repeat(add);
let id = zer+diff[key]; // "5802" -> "005802"
result += (n+1)+":"+ id +" ";
n+=1;
}
}
alert(result);
-> "1:0078965 2:087965 3:258369 4:357984 5:399710" for "176789"
答案 0 :(得分:1)
实际上,您不需要这么多不同的迭代。您只需要循环两次:
.map()
创建一个对象数组,该对象数组存储ID以及ID与num
之间的绝对差值.sort()
,将它们从最低到最高的差异进行排名第二次迭代完成后,您只需使用.slice(0, 5)
即可获取数组中的前5个对象,该数组现在包含最小的5个差异。如果您只想提取ID,请再次进行遍历:
const arr = ["087965","258369","885974","078965","457896","998120","698745","399710","357984","698745","789456"];
let num = "176789";
let m = 5; // number of final machines to find
// Create an array of objects storing the original arr + diff from `num`
const diff = arr.map(item => {
return { id: item, diff: Math.abs(+item - +num) };
});
// Sort by difference from `num` (lowest to highest)
diff.sort((a, b) => a.diff - b.diff);
// Get the first m entries
const filteredArr = diff.slice(0, m).map(item => item.id).sort();
// Log
console.log(filteredArr);
// Completely optional, if you want to format it the way you have in your question
console.log(`"${filteredArr.map((v, i) => i + ": " + v).join(', ')}" for "${num}"`);
答案 1 :(得分:0)
您可以将一个数组作为结果集,用前n
个元素填充它,然后按所需值的增量对其进行排序。
对于所有其他元素,请检查实际项目的绝对增量和该值是否小于结果集的最后一个值,然后将该值替换为实际项目。再次排序。重复直到所有元素都处理完。
通过使用目标值,结果集按最小增量到最大顺序排列。
const
absDelta = (a, b) => Math.abs(a - b),
sortDelta = v => (a, b) => absDelta(a, v) - absDelta(b, v),
array = [087965, 258369, 885974, 0078965, 457896, 998120, 698745, 399710, 357984, 698745, 789456],
value = 176789,
n = 5,
result = array.reduce((r, v) => {
if (r.length < n) {
r.push(v);
r.sort(sortDelta(value));
return r;
}
if (absDelta(v, value) < absDelta(r[n - 1], value)) {
r[n - 1] = v;
r.sort(sortDelta(value));
}
return r;
}, []);
console.log(result); // sorted by closest value
答案 2 :(得分:0)
到目前为止,有一些不错的方法,但是我无法忍受。
这将测试数组排序版本中n个元素的滑动窗口,并返回其中点最接近您要查找的值的窗口。这是一种非常有效的方法(一种数组,然后一次遍历)–尽管它无法捕获存在多个正确答案的情况(请参见下面的最后一个测试用例)。
const closestN = function(n, target, arr) {
// make sure we're not comparing strings, then sort:
let sorted = arr.map(Number).sort((a, b) => a - b);
target = Number(target);
let bestDiff = Infinity; // actual diff can be assumed to be lower than this
let bestSlice = 0; // until proven otherwise
for (var i = 0; i <= sorted.length - n; i++) {
let median = medianOf(sorted[i], sorted[i+n-1]) // midpoint of the group
let diff = Math.abs(target - median); // distance to the target
if (diff < bestDiff) { // we improved on the previous attempt
bestDiff = diff; // capture this for later comparisons
bestSlice = i;
}
// TODO handle diff == bestDiff? i.e. more than one possible correct answer
}
return sorted.slice(bestSlice, bestSlice + n)
}
// I cheated a bit here; this won't work if a > b:
const medianOf = function(a, b) {
return (Math.abs(b-a) / 2) + a
}
console.log(closestN(5, 176789, ["087965", "258369", "885974", "0078965", "457896", "998120", "698745", "399710", "357984", "698745", "789456"]))
// more test cases
console.log(closestN(3, 5, [1,2,5,8,9])) // should be 2,5,8
console.log(closestN(3, 4, [1,2,5,8,9])) // should be 1,2,5
console.log(closestN(1, 4, [1,2,5,8,9])) // should be 5
console.log(closestN(3, 99, [1,2,5,8,9])) // should be 5,8,9
console.log(closestN(3, -99, [1,2,5,8,9])) // should be 1,2,5
console.log(closestN(3, -2, [-10, -5, 0, 4])) // should be -5, 0, 4
console.log(closestN(1, 2, [1,3])) // either 1 or 3 would be correct...