Javascript 在对象数组中找到最接近的数字并检索对象的键值
Javascript find the closest number in an array of objects and retrieve the object's key value
我有一个对象数组(keys
:name
,quoteNumber
)我想找到比给定的更接近的 quoteNumber
number 然后检索该对象的名称,我考虑过使用 for 循环删除较大的值,并从剩余的值中获取最大值,但考虑到数据集有多大,它可能不是最佳选择。这是其他更有效的算法吗?谢谢!
const givenNum = 45
var array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Carrie",
quoteNumber: 47}];
//'result:' Sally
我做了一个简单的单行代码,它剔除了所有具有较大引号的元素,对其他元素进行排序,最后得到第一个元素(-> 最接近的元素):
const closest_smaller = array.filter(a => a.quoteNumber <= givenNum).sort((a,b) => b.quoteNumber-a.quoteNumber)[0]
如果 givenNum 小于每个 quoteNumber,则此 returns 未定义。
如果你想有一个后备使用:
const closest_smaller = array.filter(a => a.quoteNumber <= givenNum).sort((a,b) => b.quoteNumber-a.quoteNumber)[0] ?? 0
你也可以用find
代替filter
,我不知道哪个更快:
const closest_smaller = array.sort((a,b) => b.quoteNumber-a.quoteNumber).find(a => a.quoteNumber <= givenNum) ?? 0
如果它是未排序的,最有效的是单次传递。
function getHighestQuote(quotes, limit) {
let winner = null;
let winningQuote = null;
for (let {name, quoteNumber} of quotes) {
if (quoteNumber > limit)
continue;
if (winningQuote === null || winningQuote < quoteNumber) {
winner = name;
winningQuote = quoteNumber;
}
}
return winner;
}
它不像函数式方法那么时髦,但它是一个线性时间传递,只需要分配几个堆栈变量。
如果您有一个大型数据集,您希望避免做任何在数组上循环不止一次,甚至在查看之前尝试对其进行排序的操作。一个简单的聚合操作就可以做到这一点。使用 reduce
const givenNum = 45
var array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Carrie",
quoteNumber: 47}];
const result = array.reduce ( (acc,item) => {
const diff = givenNum - item.quoteNumber;
if(item.quoteNumber < givenNum && diff < acc.diff)
acc = {diff, item}
return acc;
},{ diff: Number.MAX_SAFE_INTEGER, item: null });
console.log(result.item);
另请注意,如果速度真的 很重要,也请避免使用此解决方案 - 它有额外的方法调用,您不会使用更简单的 。这将总是 是最快的选择。
这是基于@Jeremy Roman 和@Jamiec 的回答。我认为这要快一点,除非我做了一些愚蠢的事情:https://jsbench.me/g0kmha8buo/1
const array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Velma",
quoteNumber: 31},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Neva",
quoteNumber: 30},
{ name: "Carrie",
quoteNumber: 47},
{ name: "Arnold",
quoteNumber: 29},
];
function closest_quote_less_than_or_equal_to(quotes, limit) {
let winner = null;
let winningQuote = 0;
const limit_plus_one = limit + 1;
for(let i = 0; i < quotes.length; i++) {
const quoteNumber = quotes[i].quoteNumber;
if(((quoteNumber < limit_plus_one) * quoteNumber) > winningQuote) {
winningQuote = quoteNumber;
winner = quotes[i].name;
}
}
return winner;
}
console.log(closest_quote_less_than_or_equal_to(array, 45));
console.log(closest_quote_less_than_or_equal_to(array, 30));
console.log(closest_quote_less_than_or_equal_to(array, 10));
我有一个对象数组(keys
:name
,quoteNumber
)我想找到比给定的更接近的 quoteNumber
number 然后检索该对象的名称,我考虑过使用 for 循环删除较大的值,并从剩余的值中获取最大值,但考虑到数据集有多大,它可能不是最佳选择。这是其他更有效的算法吗?谢谢!
const givenNum = 45
var array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Carrie",
quoteNumber: 47}];
//'result:' Sally
我做了一个简单的单行代码,它剔除了所有具有较大引号的元素,对其他元素进行排序,最后得到第一个元素(-> 最接近的元素):
const closest_smaller = array.filter(a => a.quoteNumber <= givenNum).sort((a,b) => b.quoteNumber-a.quoteNumber)[0]
如果 givenNum 小于每个 quoteNumber,则此 returns 未定义。 如果你想有一个后备使用:
const closest_smaller = array.filter(a => a.quoteNumber <= givenNum).sort((a,b) => b.quoteNumber-a.quoteNumber)[0] ?? 0
你也可以用find
代替filter
,我不知道哪个更快:
const closest_smaller = array.sort((a,b) => b.quoteNumber-a.quoteNumber).find(a => a.quoteNumber <= givenNum) ?? 0
如果它是未排序的,最有效的是单次传递。
function getHighestQuote(quotes, limit) {
let winner = null;
let winningQuote = null;
for (let {name, quoteNumber} of quotes) {
if (quoteNumber > limit)
continue;
if (winningQuote === null || winningQuote < quoteNumber) {
winner = name;
winningQuote = quoteNumber;
}
}
return winner;
}
它不像函数式方法那么时髦,但它是一个线性时间传递,只需要分配几个堆栈变量。
如果您有一个大型数据集,您希望避免做任何在数组上循环不止一次,甚至在查看之前尝试对其进行排序的操作。一个简单的聚合操作就可以做到这一点。使用 reduce
const givenNum = 45
var array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Carrie",
quoteNumber: 47}];
const result = array.reduce ( (acc,item) => {
const diff = givenNum - item.quoteNumber;
if(item.quoteNumber < givenNum && diff < acc.diff)
acc = {diff, item}
return acc;
},{ diff: Number.MAX_SAFE_INTEGER, item: null });
console.log(result.item);
另请注意,如果速度真的 很重要,也请避免使用此解决方案 - 它有额外的方法调用,您不会使用更简单的
这是基于@Jeremy Roman 和@Jamiec 的回答。我认为这要快一点,除非我做了一些愚蠢的事情:https://jsbench.me/g0kmha8buo/1
const array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Velma",
quoteNumber: 31},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Neva",
quoteNumber: 30},
{ name: "Carrie",
quoteNumber: 47},
{ name: "Arnold",
quoteNumber: 29},
];
function closest_quote_less_than_or_equal_to(quotes, limit) {
let winner = null;
let winningQuote = 0;
const limit_plus_one = limit + 1;
for(let i = 0; i < quotes.length; i++) {
const quoteNumber = quotes[i].quoteNumber;
if(((quoteNumber < limit_plus_one) * quoteNumber) > winningQuote) {
winningQuote = quoteNumber;
winner = quotes[i].name;
}
}
return winner;
}
console.log(closest_quote_less_than_or_equal_to(array, 45));
console.log(closest_quote_less_than_or_equal_to(array, 30));
console.log(closest_quote_less_than_or_equal_to(array, 10));