adan11
adan11

Reputation: 787

Get the 5 largest key/value in a Javascript object

I'm new to Javascript and looking for the best performing way to get the keys of the 5 largest values in a object into a new object.

eg, the object:

let object= {
  a: 5, 
  b: 87,
  c: 4,
  d: 33,
  e: 5, 
  f: 99,
  g: 1,
  h: 10,
  i: 3,
  j: 43,
};

would return

object= {
  b: 87,
  d: 33,
  f: 99,
  h: 10,
  j: 43,
};

I know this can be done by just looping through each item and comparing with each other, but wondering if theres a better way of doing this in Javascript for performance.

Thanks,

Upvotes: 1

Views: 79

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075129

I know this can be done by just looping through each item and comparing with each other, but wondering if theres a better way...

As Pointy said, this process is intrisically iterative, you can't avoid a loop and you can't avoid at least a little inner loop.

Here's a way that minimizes looping, see comments:

// Start with an empty array
let top5 = [];
// Add [name, value] pairs to it
for (const key in object) {
    const thisValue = object[key];
    // Is this value greater than an existing one?
    // (This is a small inner loop, hidden in the `findIndex` call.)
    const index = top5.findIndex(([_, value]) => thisValue > value);
    if (index !== -1) {
        // Yes, insert it into the array at that location
        // (There's a small loop hidden here too: copying later entries
        // back one place in the array)
        top5.splice(index, 0, [key, thisValue]);
        // If the array is (now) > 5 entries, remove the last
        if (top5.length > 5) {
            top5.pop();
        }
    } else if (top5.length < 5) {
        // The value wasn't greater than an existing one, but
        // the array still needs values; add it at the end
        top5.push([key, thisValue]);
    }
}
// Convert back to an object
top5 = Object.fromEntries(top5);

Live:

let object= {
  a: 5, 
  b: 87,
  c: 4,
  d: 33,
  e: 5, 
  f: 99,
  g: 1,
  h: 10,
  i: 3,
  j: 43,
};
// Start with an empty array
let top5 = [];
// Add [name, value] pairs to it
for (const key in object) {
    const thisValue = object[key];
    // Is this value greater than an existing one?
    // (This is a small inner loop, hidden in the `findIndex` call.)
    const index = top5.findIndex(([_, value]) => thisValue > value);
    if (index !== -1) {
        // Yes, insert it into the array at that location
        // (There's a small loop hidden here too: copying later entries
        // back one place in the array)
        top5.splice(index, 0, [key, thisValue]);
        // If the array is (now) > 5 entries, remove the last
        if (top5.length > 5) {
            top5.pop();
        }
    } else if (top5.length < 5) {
        // The value wasn't greater than an existing one, but
        // the array still needs values; add it at the end
        top5.push([key, thisValue]);
    }
}
// Convert back to an object
top5 = Object.fromEntries(top5);
console.log(top5);

Note that top5 is always in order with the highest value first, to minimize how far into the array we have to go by knocking out value early if it's lower than the highest value we know (the first one in the array).

I haven't tried to retain the property order, not least because although properties have order (now), relying on that order is almost always a bad idea.

Upvotes: 0

AzC
AzC

Reputation: 71

I would convert them to a map, sort them then take the first 5 and convert them back to an object, here is a step by step breakdown:

const object= {
  a: 5, 
  b: 87,
  c: 4,
  d: 33,
  e: 5, 
  f: 99,
  g: 1,
  h: 10,
  i: 3,
  j: 43,
};

const newMap = Object.entries(object);

const sortedMap = newMap.sort((item1, item2) => item2[1] - item1[1]);

const top5Map = sortedMap.slice(0,5)

const top5 = Object.fromEntries(top5Map);

console.log(top5)

Upvotes: 2

Related Questions