Home > front end >  Get the nearest object key from object containing multiple objects with numeric keys
Get the nearest object key from object containing multiple objects with numeric keys

Time:05-17

I have an object containing an undefined number of child objects which are associated by numeric values as the object keys. What I need is a way to pass in a numeric number (currency) and get the child object that is the closest to the number I pass into the function.

Example Object structure

{
"32.5": [
{
  "key": "value",
  "key": "value"
},
{
  "key": "value",
  "key": "value"
}
],
"34": [
{
  "key": "value",
  "key": "value"
}
],
"35.5": [
{
  "key": "value",
  "key": "value"
}
]
}

The keys of the object are strings, so I already figured out I probably somehow have to parse the object keys to a number for comparison but I am completely lost on how to tie it all together.

I declared a function that takes 3 parameters which at the end should return the child object where its key is the closest to my input parameter.

function getNearest(obj, decimalNumber, below_or_above)

when I put in "above" I want to get the closest key where its number value is the next higher, when I put in "below" it would return the next object where its number key is the next smaller.

If I would call getNearest(obj, 33.4, above) it should return the object with the key "34".

I hope I managed somehow to explain so everyone can understand..

This is the starting point I came up with but I don't know how to proceed from here

    function getNearest(obj, decimalNumber, above_or_below){
    const keys = [];
    Object.keys(obj).forEach(key =>{
        let numericKey = Number(key);
        keys.push(numericKey);
    })

    //store all numeric keys in array to further process later on
    }

CodePudding user response:

  • Transform the object into an array of items using Object.entries.
  • Loop over the object using Array.prototype.map and convert the string keys to numbers, to perform comparisons correctly.
  • Sort the array by the keys using Array.prototype.sort.
  • Find the key based on the pos argument using Array.prototype.find.
  • Finally return the value corresponding to the found key.

const 
  data = { 32.5: [{ key: "32.5" }], 34: [{ key: "34" }], 35.5: [{ key: "35.5" }] },
  getKey = (obj, target, pos) =>
    Object.entries(obj)
      .map(([k, v]) => [Number(k), v])
      .sort(([a], [b]) => a - b)
      .find(([k], i, a) =>
        pos === "above"
          ? k >= target
          : k <= target && (a[i   1]?.[0] > target || i === a.length - 1)
      )?.[1];

console.log(getKey(data, 33, "above")); // [{ key: "34" }]
console.log(getKey(data, 33, "below")); // [{ key: "32.5" }]
console.log(getKey(data, 37, "above")); // undefined
console.log(getKey(data, 30, "below")); // undefined

Table for reference:

target below above
0 undefined [{ key: '32.5' }]
31.4 undefined [{ key: '32.5' }]
32.5 [{ key: '32.5' }] [{ key: '34' }]
32.8 [{ key: '32.5' }] [{ key: '34' }]
33.4 [{ key: '32.5' }] [{ key: '34' }]
34 [{ key: '34' }] [{ key: '34' }]
35.1 [{ key: '34' }] [{ key: '35.5' }]
35.5 [{ key: '35.5' }] [{ key: '35.5' }]
50 [{ key: '35.5' }] undefined

CodePudding user response:

You could

  • get keys from the object,
  • map numbers,
  • sort array to adjust native object sorting (positev 32 bit integer first),
  • find the value by check if smaller than value or hitting last item or if the absolute delta of actual and next item is smaller.
 value   below   above
------- ------- -------                
  0     undef    32.5
 31.4   undef    32.5
 32.5    32.5    34
 32.8    32.5    34
 33.4    32.5    34
 34      34      34
 35.1    34      35.5
 35.5    35.5    35.5
 50      35.5    undef

 isAbove false    true

const
    getKey = (object, value, isAbove) => Object
        .keys(object)
        .map(Number)
        .sort((a, b) => a - b)
        .find((v, i, a) => isAbove
            ? v >= value
            : v <= value && (a[i   1] > value || i   1 === a.length)
        ),
    data = { 32.5: [{}], 34: [{}], 35.5: [{}] };

console.log('below');
console.log(getKey(data, 0)); // 32.3
console.log(getKey(data, 31.4)); // 32.3
console.log(getKey(data, 32.5)); // 32.3
console.log(getKey(data, 32.8)); // 32.3
console.log(getKey(data, 33.4)); // 34
console.log(getKey(data, 34)); // 34
console.log(getKey(data, 35.1)); // 35.5
console.log(getKey(data, 35.5)); // 35.5
console.log(getKey(data, 100)); // 35.5

console.log('above');
console.log(getKey(data, 0, true)); // 32.3
console.log(getKey(data, 31.4, true)); // 32.3
console.log(getKey(data, 32.5, true)); // 32.3
console.log(getKey(data, 32.8, true)); // 32.3
console.log(getKey(data, 33.4, true)); // 34
console.log(getKey(data, 34, true)); // 34
console.log(getKey(data, 35.1, true)); // 35.5
console.log(getKey(data, 35.5, true)); // 35.5
console.log(getKey(data, 100, true)); // 35.5
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related