Ilja Leiko
Ilja Leiko

Reputation: 648

Sort nested dictionary by value in JS

Can someone please help to figure out the way to sort a dictionary with another dictionary inside in JavaScript? This is how my dict looks like:

{'POS2': {'stegano': 0, 'sum': 200, 'misc': 100, 'web': 0, 'ppc': 0, 'crypto': 0, 'admin': 0, 'vuln': 0, 'forensics': 0, 'hardware': 0, 'reverse': 0, 'recon': 100}, ...}

I want to sort it by 'sum' key that is stored in nested dict. I can find some solutions written in python, but the challenge here is to achieve the same functionality in JS. Would appreciate any help.

Upvotes: 0

Views: 1733

Answers (3)

Sergey Shulik
Sergey Shulik

Reputation: 1010

For example, you have next array (similar to your array, but has less properties to readable):

let obj = {
    pos1: { sum: 100, name: 'p1' },
    pos2: { sum: 1, name: 'p2' },
    pos3: { sum: 50, name: 'p3' }
};

var result = Object.keys(obj)
    .map(key => { return {key, val: obj[key]}}) // output: unsorted array
    .sort((a, b) => a.val.sum > b.val.sum); 

console.log(result);

and as result you will see:

[ { key: 'pos2', val: { sum: 1, name: 'p2' } },
  { key: 'pos3', val: { sum: 50, name: 'p3' } },
  { key: 'pos1', val: { sum: 100, name: 'p1' } } ]

Upvotes: 0

Andy
Andy

Reputation: 63524

Since you can't order objects by property you'd need to map the objects to an array and then sort that. And you'd probably not want to lose the key for each nested object (like POS2), so you'd want to embed that key in the object for safe-keeping.

const obj = {"POS2":{"stegano":0,"sum":2200,"misc":100,"web":0,"ppc":0,"crypto":0,"admin":0,"vuln":0,"forensics":0,"hardware":0,"reverse":0,"recon":100},"POS3":{"stegano":0,"sum":1200,"misc":100,"web":0,"ppc":0,"crypto":0,"admin":0,"vuln":0,"forensics":0,"hardware":0,"reverse":0,"recon":100},"POS4":{"stegano":0,"sum":22,"misc":100,"web":0,"ppc":0,"crypto":0,"admin":0,"vuln":0,"forensics":0,"hardware":0,"reverse":0,"recon":100},"POS5":{"stegano":0,"sum":2001,"misc":100,"web":0,"ppc":0,"crypto":0,"admin":0,"vuln":0,"forensics":0,"hardware":0,"reverse":0,"recon":100}}

// map over the object keys
const out = Object.keys(obj).map(key => {

  // on each iteration return the object with its new key property
  return { ...obj[key], key }

// then sort the array of object by their sums
}).sort((a, b) => a.sum - b.sum);

console.log(out);

Upvotes: 0

Icepickle
Icepickle

Reputation: 12796

Just retrieve the inner object using Object.values and then use Array.sort to sort by it's content. Note that you cannot sort an objects properties as they are per default an unsorted set (or at least, it's not properly described how properties should be sorted on an object)

const dict = {
  'POS2': {
    'stegano': 0, 
    'sum': 200, 
    'misc': 100, 
    'web': 0, 
    'ppc': 0, 
    'crypto': 0, 
    'admin': 0, 
    'vuln': 0, 
    'forensics': 0, 
    'hardware': 0, 
    'reverse': 0, 
    'recon': 100
  }, 
  'POS1': {
    'sum': 100
  },
  'POS3': {
    'sum': 250
  }
};

function orderBySubKey( input, key ) {
  return Object.values( input ).map( value => value ).sort( (a, b) => a[key] - b[key] );
}

console.log( orderBySubKey( dict, 'sum' ) );

This sample would remove the outer properties, if you want to keep these, you can change your ordering a bit, for example like

const dict = {
  'POS2': {
    'stegano': 0, 
    'sum': 200, 
    'misc': 100, 
    'web': 0, 
    'ppc': 0, 
    'crypto': 0, 
    'admin': 0, 
    'vuln': 0, 
    'forensics': 0, 
    'hardware': 0, 
    'reverse': 0, 
    'recon': 100
  }, 
  'POS1': {
    'sum': 100
  },
  'POS3': {
    'sum': 250
  }
};

function orderBySubKey( input, key ) {
  return Object.keys( input ).map( key => ({ key, value: input[key] }) ).sort( (a, b) => a.value[key] - b.value[key] );
}

console.log( orderBySubKey( dict, 'sum' ) );

Which gives you a different output, but would still allow you to lookup inside the original dictionary

Upvotes: 2

Related Questions