繁体   English   中英

在数组中查找具有最接近值的对象

[英]Find object in array with closest value

我需要通过最接近的值获取数组中的对象。 让我通过一个例子来解释它:

const data = [
  { age: 52 },
  { age: 53 },
  { age: 54 },
  { age: 60, some: 'data' },
  { age: 66, something: 'else' },
  { age: 72 },
  { age: 78 },
  { age: 84 }
]

我确实通过使用data.find((d)=> d.age === 60)来获取对象。 但是如果年龄是61我不会得到结果。 在这种情况下,我想获得相同的对象。

对于64 ,应该返回下一个对象( { age: 66, something: 'else' } )。

如您所见,年龄值不是线性的。

你可以找到所有的区别的数量和哪一个是最接近零将是你的结果,要达到这个我已经使用.reduce()Math.abs()

 const data = [ { age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 } ]; const getAge = (data, target) => data.reduce((acc, obj) => Math.abs(target - obj.age) < Math.abs(target - acc.age) ? obj : acc ); console.log(getAge(data, 61)); // {age: 60} console.log(getAge(data, 50)); // {age: 52} console.log(getAge(data, -1)); // {age: 52} console.log(getAge(data, 90)); // {age: 84}

这也适用于具有除age之外的其他属性的更通用的对象。

这是解决您的问题的完全抽象的方法:

 // Saves up vertical space const data = JSON.parse(`[{"age":52},{"age":53},{"age":54},{"age":60},{"age":66},{"age":72},{"age":78},{"age":84}]`); function getClosestValue(list, getDifference) { var smallestDiff = Infinity; return list.reduce(function(closestValue, currentValue, index) { var newDifference = Math.abs(getDifference(currentValue)); if (!index) return smallestDiff = newDifference, currentValue; return smallestDiff = Math.min(smallestDiff, newDifference), newDifference === smallestDiff ? currentValue : closestValue; }); } function getClosestAge(list, age) { return getClosestValue(list, function(listValue) { return listValue.age - age; }); } console.log(getClosestAge(data, 65));

如果它总是排序,你可以使用some

 // Saves up vertical space const data = JSON.parse(`[{"age":52},{"age":53},{"age":54},{"age":60},{"age":66},{"age":72},{"age":78},{"age":84}]`); function getClosestValue(list, getDifference) { var smallestDiff = Infinity; var closestValue; list.some(function(currentValue, index) { var newDifference = Math.abs(getDifference(currentValue)); if (!index) return smallestDiff = newDifference, closestValue = currentValue, false; if (smallestDiff > newDifference) return smallestDiff = newDifference, closestValue = currentValue, false; else if (smallestDiff !== newDifference) return true; }); return closestValue; } function getClosestAge(list, age) { return getClosestValue(list, function(listValue) { return listValue.age - age; }); } console.log(getClosestAge(data, 65));

假设您的列表未排序,并且您不想对列表进行排序。 所以你可以选择第一个对象,遍历你的列表并检查你是否得到一个项目,它比你当前选择的项目更符合你的要求。 如果是这样,您只需用更好的物品替换您的物品。

例如

var data = [/*...*/];
var find_age = 64;           // input
var best_item = data[0];     // pick any item as best item
for (var i = 1; i < data.length; i++) {

  // does date[i] match the requirement better than best_item?
  if (Math.abs (best_item.age - find_age) > Math.abs (data[i].age - find_age)) {

    // it does ... so update best_item
    best_item = data[i];
  }
}

// best_item stores the item which matches your requirement most.

如果您的数据集已排序,则可以优化运行时。

您可以通过差异对数组进行排序以查找年龄:

 const lookupAge = 61 const data = [ { age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 } ] const result = data .map(d => d.age) .sort((a, b) => Math.abs(a - lookupAge) - Math.abs(b - lookupAge)) console.log('result', result)

 const data = [ { age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 } ]; const find = 64; const result = data.map(({ age }) => age).reduce((best, el, index) => { if (Math.abs(find - el) < Math.abs(find - best)) { return el; } return best; }, data[0].age) console.log(result)

您可以通过从每个元素中减去给定的数字并取绝对值来找到最小差异,然后进行更高的查找和更低的查找

它还会考虑何时有 2 个不同的最接近值

 const data = [ { age: 52 }, { age: 53 }, { age: 55 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 } ] function minimum(given){ //let given=54 //find the mimimun different let closest_diff=Math.min(...data.map(a=>Math.abs(a.age-given))) //for lower closest number let x1=data.find(a=>a.age===given-closest_diff); //for highter closest number let x2=data.find(a=>a.age===given+closest_diff); //filter the number which are in array above console.log(...new Set([x1,x2].filter(x=>x))); } minimum(52); //52 minimum(54); //53 and 55 minimum(63); //60 and 66 minimum(75); //72 and 78 minimum(77); //78

对于已排序的数据,您可以将具有最大值的数据作为起始值从头开始迭代,如果增量增长则停止迭代。

 var data = [{ age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 }], result = data[data.length - 1], age = 61; data.some((o) => { if (Math.abs(age - o.age) >= Math.abs(age - result.age)) return true; result = o; }); console.log(result);

我做了一个小片段代码来向你展示我会这样做的方式。 这将创建在任何对象数组上使用findClosest方法,该方法需要一个属性名称和一个值。 然后,该函数将返回数组中与给定属性值最接近的元素。 它可以改进,但效果很好。

 document.addEventListener("DOMContentLoaded", function() { const listElem = document.getElementById('list'); const closestElem = document.getElementById('closest'); data.forEach(elem => { const listElemEntry = document.createElement('li'); listElemEntry.innerHTML = elem.age; listElem.appendChild(listElemEntry); }); const closest = data.findClosest('age', 80); closestElem.innerHTML = closest; }); const data = [ { age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 } ]; Array.prototype.findClosest = function(attr, value) { const closestElem = { diff: Infinity, index: -1 }; this.forEach((elem, index) => { const diff = Math.abs(elem[attr] - value); if (diff < closestElem.diff) { closestElem.diff = diff; closestElem.index = index; } }); return this[closestElem.index][attr]; }
 <h2>Elements list</h2> <ul id="list"></ul> <h2>Closest element</h2> <pre id="closest"></pre>

您可以找到最接近的数组项,其差异最小值如下所示;

function getClosest(data, x) {
    if (data.length == 0) {
        return null;
    }
    var index = 0;
    var difference = Number.MAX_SAFE_INTEGER;
    for(var i = 0; i<data.length;i++) {    
        if (i < data.length) {
            var differ =  Math.abs(data[i].age - x);           
            if(differ < difference) {
                difference = differ;
                index = i;    
            }        
        }   
    }
    return data[index];
}

用法:

getClosest(data, 64)
Suppose array isn't sorted. Following function returns result. If it find value that is equal to search value, it stops searching, so it is a small gain in performance.

function minDiff(data, val) {
    let res = null;
    let n = data.length;
    let diffGet = (val1, val2) => Math.abs(val1 - val2);

    if (n>0) {
        res = data[0];
        let diff = diffGet(res.age, val);
        let i = 1;
        while ( diff>0 && i<n ) {
            if (diffGet(data[i].age, val) < diff) {
                res = data[i];
                diff = diffGet(res.age, val);                
            }
            i++;            
        }        
    }

    return res;

}

这是解决柯里化问题的一种功能方法:

 const data = [ { age: 52 }, { age: 53 }, { age: 54 }, { age: 60, some: "data" }, { age: 66, something: "else" }, { age: 72 }, { age: 78 }, { age: 84 } ]; const indexOfSmallest = (array) => { if (array.length === 0) { throw new Error("Empty array, expects at least one element"); } return array.reduce((lowest, next, index) => { if (next < array[lowest]) { return index; } return lowest; }, 0); }; const getClosestIndex = (numbers, referenceNumber) => { const diff = numbers.map(n => Math.abs(referenceNumber - n)); return indexOfSmallest(diff); }; const createGetClosestIndex = (numbers) => (number) => getClosestIndex(numbers, number); const createGetClosestPerson = (people) => { return (targetAge) => { const numbers = people.map(d => d.age); const index = createGetClosestIndex(numbers)(targetAge); return people[index]; }; }; const getClosest = createGetClosestPerson(data); console.log(getClosest(1), getClosest(64));

@nick-parsons 优秀答案的通用版本...

 function closest (num, arr, key=null) { if (key==null) { return arr.reduce((a, b) => Math.abs(num - b) < Math.abs(num - a) ? b : a); } return arr.reduce((a, b) => { if (b[key] == null) return a; if (a[key] == null) return b; return Math.abs(num - b[key]) < Math.abs(num - a[key]) ? b : a; }); } let arr = [ {speed: 0.1}, {speed: 0.4}, {speed: 1} ] console.log( closest(0.5, arr, "speed").speed ) // output: 0.4 arr = [ 0.1, 0.4, 1 ] console.log( closest(0.9, arr) ) // output: 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM