Javascript 在对象数组中找到最接近的数字并检索对象的键值

Javascript find the closest number in an array of objects and retrieve the object's key value

我有一个对象数组(keysnamequoteNumber)我想找到比给定的更接近的 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));