1

I have the following object:

let res = {
   'name': {
      age: 10,
      density: 33,
      length: 2
    },
    'greet': {
       age: 33,
       density: 92,
       length: 3
    },
    'gyrt': {
        age: 91,
        density: 2,
        length: 47
     },
     .
     .
     .
}

Which has much more key value pairs. I am asked to return the list of keys in the descending order of "ranking" which is governed by the below constraints:

  • Greater age must be ranked higher
  • Words with low density must be ranked higher
  • Words with high length must be ranked higher

I am confused how to achieve this. I am trying to sort object but that does not help. I first tried to sort with age, then with density, and then with length but it clearly does not work because object is re-ordered again and again while forgetting the previous order. How could I achieve this?

This is what I was trying:

let sortByAge = keys.sort((a, b) => Number(res[b].age) - Number(res[a].age));

let sortByDensity = keys.sort((a, b) => Number(res[b].density) - Number(res[a].density));

And same with length. I cannot understand how to combine all the factors and order them.

Luca Kiebel
  • 9,790
  • 7
  • 29
  • 44
Henry Ron
  • 13
  • 3

2 Answers2

1

You just have to put some conditions into your sort function that check whether or not the age, or the density are equal, and if they are, sort by the next set of rules (age -> density -> length):

let a={'name':{age:10,density:33,length:2},'greet':{age:33,density:92,length:3},'gyrt':{age:91,density:2,length:47},'foo':{age:91,density:3,length:47},'bar':{age:91,density:2,length:30},'baz':{age:10,density:2,length:47},'boo':{age:91,density:2,length:47},}

let sorted = Object.values(a);

sorted.sort((a,b) => {
  if(a.age === b.age) {
    if(a.density === b.density) {
      //sort by length
      return b.length - a.length;
    }
    //sort by density
    return a.density - b.density;
  }
  //sort by age
  return b.age - a.age;
});

console.log(sorted)

To sort the keys (sorting values is better for showing how it works), just replace a and b by obj[a] and obj[b]

let obj={'name':{age:10,density:33,length:2},'greet':{age:33,density:92,length:3},'gyrt':{age:91,density:2,length:47},'foo':{age:91,density:3,length:47},'bar':{age:91,density:2,length:30},'baz':{age:10,density:2,length:47},'boo':{age:91,density:2,length:47},}

let sorted = Object.keys(obj);

sorted.sort((a,b) => {
  if(obj[a].age === obj[b].age) {
    if(obj[a].density === obj[b].density) {
      //sort by length
      return obj[b].length - obj[a].length;
    }
    //sort by density
    return obj[a].density - obj[b].density;
  }
  //sort by age
  return obj[b].age - obj[a].age;
});

console.log(sorted)
Luca Kiebel
  • 9,790
  • 7
  • 29
  • 44
  • 1
    Words with greater `age` must be ranked higher. Words with low `density` must be ranked higher. Currently it prints age with 10 on the top. – Henry Ron Sep 13 '18 at 21:29
  • Check it now please – Luca Kiebel Sep 13 '18 at 21:29
  • Just realized it, I changed it a total of one million times while writing the answer ^^ – Luca Kiebel Sep 13 '18 at 21:29
  • 1
    Also, how could I get just the `keys`? – Henry Ron Sep 13 '18 at 21:31
  • I added an example of how to do that as well – Luca Kiebel Sep 13 '18 at 21:34
  • How could I modify this if the condition changes to `Words with high density must be ranked higher`? – Henry Ron Sep 13 '18 at 21:42
  • invert the order of `obj[a].density - obj[b].density;`, so that `obj[a]` gets subtracted from `obj[b]`, to `obj[b].density - obj[a].density;` – Luca Kiebel Sep 13 '18 at 21:44
  • 1
    I was trying with a different condition here at [jsfiddle](http://jsfiddle.net/7zrkvqd3/) , where high rank will be ranked higher, high occurance will be ranked higher and low length will be ranked higher. But I am making some mistake as I try to emulate your method. Could you please help me with this? – Henry Ron Sep 13 '18 at 21:52
  • @PatrickRoberts It does not work. The occurances and length are both jumbled up. – Henry Ron Sep 13 '18 at 21:56
  • @HenryRon Consider what you're saying. The `occurances` are only used as a criteria if the `rank` is the same, and the `length` are only used as a criteria if both the `rank` and `occurances` are the same. – Patrick Roberts Sep 13 '18 at 21:58
0

Using the sortBy() function I introduced here, you can create a sorting method that combines each property like so:

const res = {name:{age:10,density:33,length:2},greet:{age:33,density:92,length:3},gyrt:{age:91,density:2,length:47},foo:{age:91,density:3,length:47},bar:{age:91,density:2,length:30},baz:{age:10,density:2,length:47},boo:{age:91,density:2,length:47}}

const sortBy = fn => (a, b) => -(fn(a) < fn(b)) || +(fn(a) > fn(b))
const pick = key => ({ [key]: value }) => value
const age = sortBy(pick('age'))
const density = sortBy(pick('density'))
const length = sortBy(pick('length'))
const sortFn = (a, b) =>
  -age(a[1], b[1]) ||
  density(a[1], b[1]) ||
  -length(a[1], b[1])

const keys = Object.entries(res).sort(sortFn).map(([key, value]) => key)

console.log(keys)
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153