1

Help me to write a function which will sort an object :

I have an object like which will sort according to its key inside 'order':

var users = {
  certificate:'certificate of student',
  lessons:  {
        lession_1: { 'user': 'fred',   'order': 1 },
        lession_2: { 'user': 'barney', 'order': 2 },
        lession_4: { 'user': 'fred',   'order': 4 },
        lession_3: { 'user': 'barney', 'order': 3 }
    }
}; 

it should be after sorting:

var users = {
  certificate:'certificate of student',
  lessons:  {
        lession_1: { 'user': 'fred',   'order': 1 },
        lession_2: { 'user': 'barney', 'order': 2 },
        lession_3: { 'user': 'barney', 'order': 3 },
        lession_4: { 'user': 'fred',   'order': 4 }
    }
}; 
Abhi
  • 81
  • 1
  • 8

4 Answers4

0
  1. First you need turn lessons object to array, because sort work only with Array.

    const arrayLessons = Object.values(users.lessons);

  2. Now sorting the arrayLessons using sort.

    const sortedArray = arrayLessons.sort((prev, next) => prev.order - next.order);

  3. Update data for object of users

    users.lessons = sortedArray;

Alexander
  • 1,220
  • 6
  • 12
  • 1
    Code-only answers are considered low quality: make sure to provide an explanation what your code does and how it solves the problem. It will help the asker and future readers both if you can add more information in your post. See also Explaining entirely code-based answers: https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers – borchvm Jan 16 '20 at 12:14
0

Since you can't sort keys of an object, you'll have to:

  1. Transform the object into an array.
  2. Sort the array.
  3. Transform the array back into an object.

Here is an efficient way of doing that:

var users = {
  certificate:'certificate of student',
  lessons:  {
        lession_1: { 'user': 'fred',   'order': 1 },
        lession_2: { 'user': 'barney', 'order': 2 },
        lession_4: { 'user': 'fred',   'order': 4 },
        lession_3: { 'user': 'barney', 'order': 3 }
   }
}; 

function sortLessons (obj) {
    obj.lessons = Object.entries(obj.lessons)
        .sort((prev, next) => prev[1].order - next[1].order)
        .reduce((acc, value) => {
            acc[value[0]] = value[1];
            return acc;
        }, {});
}

sortLessons(users);

console.log(users);

The Object.entries returns an array [key, value] for each entries.

Then the sort function takes a compareFunction, the documentation says:

If compareFunction(a, b) returns greater than 0, sort b to an index lower than a (i.e. b comes first).

By doing the difference a - b, in your case 4-3 = 1, the lesson_3 will be inserted before lesson_4 and your array will be sorted.

Then the reduce function rebuilds the object.

Mickael B.
  • 4,755
  • 4
  • 24
  • 48
  • @Alexander Good catch, It has been fixed ! – Mickael B. Jan 16 '20 at 12:04
  • Why do you think your solution is the most effective? In fact, you are doing 3 loop, when can two. – Alexander Jan 16 '20 at 12:42
  • It is more effective in term of readability, development time and coding style and sometimes performance since standard library can be more optimized than custom algorithm using loops. Also you can't use 2 loops (if you refer to your answer it is incomplete with a wrong result) to answer the author question. – Mickael B. Jan 16 '20 at 13:10
  • i mean re-usability, like i can pass parameter to a function like wise : (obj, lessons, order). – Abhi Jan 16 '20 at 14:25
  • Ok, so the `lessons` is already in the `users` object so you dont' need to pass it has parameter and for the `order` you probably mean the sort function you can just put it as parameter of the function. Is it good like that or you want me to edit the answer ? – Mickael B. Jan 16 '20 at 14:46
0

Key order for non-symbol properties are now determined by insertion order (as of ES6). With this in mind, you can extract the values of your lesson object, and then sort each object in your array of objects with .sort(). You can then loop over your sorted array and insert your objects into a new .lessons object in the order they appear in the sorted order array like so:

const users = {
  certificate: 'certificate of student',
  lessons: {
    lession_1: {
      'user': 'fred',
      'order': 1
    },
    lession_2: {
      'user': 'barney',
      'order': 2
    },
    lession_4: {
      'user': 'fred',
      'order': 4
    },
    lession_3: {
      'user': 'barney',
      'order': 3
    }
  }
};

const sortObj = (obj) => {
  const order = Object.entries(obj.lessons).sort(([,a], [,b]) => a.order-b.order);
  obj.lessons = {};
  for(const [lesson, user] of order)
    obj.lessons[lesson] = user;

}

sortObj(users)
console.log(users);

However, I would suggest that you lean towards using arrays instead of objects if you're going to be working with ordering objects as it is much more intuitive:

const users = {
  certificate: 'certificate of student',
  lessons: [
    {
      'user': 'fred',
      'order': 1
    },
    {
      'user': 'barney',
      'order': 2
    },
    {
      'user': 'fred',
      'order': 4
    },
    {
      'user': 'barney',
      'order': 3
    }
  ]
};

const sortObj = (obj) => {
  obj.lessons.sort((a, b) => a.order-b.order);
}

sortObj(users)
console.log(users);
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
  • Is something wrong with my answer? Please let me know if I've got something incorrect (not too sure what I've missed) – Nick Parsons Jan 16 '20 at 12:09
  • The `obj.lessons["lesson_"+(i+1)]` with hard coded value. You have to update your algorithm every time you'll update you're data. Also the loop for rebuilding the object is not really efficient when there is available builtin functions for that (see [my answer](https://stackoverflow.com/a/59768967/9434800)) – Mickael B. Jan 16 '20 at 12:19
  • Yes, it is hardcoded, that could be improved. But I wouldn't say that it makes this answer incorrect. I've updated it now to get the object's entries rather than hardcoding it. As for using a loop to rebuild the object, using `.reduce()` is also rebuilding the object under the hood, both perform the re-build logic. So using reduce isn't much more efficient than using a standard loop – Nick Parsons Jan 16 '20 at 12:35
  • I think it's better to use what your language has to offer rather than reinventing the wheel. Otherwise you could say the same thing for the `entries` or `sort` functions, actually for all the standard library since you could write all your code using `for` loops and `if` statements. It is more efficient in term of development time to use what already exists and also in term of clarity when you want to read your code later (a function is for a specific task when a loop could do anything) and sometimes performance since standard library could be optimized. – Mickael B. Jan 16 '20 at 13:02
0

Try Following:-

var users = {
  certificate:'certificate of student',
  lessons:  {
        lession_1: { 'user': 'fred',   'order': 1 },
        lession_2: { 'user': 'barney', 'order': 2 },
        lession_4: { 'user': 'fred',   'order': 4 },
        lession_3: { 'user': 'barney', 'order': 3 }
    }
}; 

keysSorted = Object.keys(users.lessons).sort(function(a,b){return users.lessons[a]['order']-users.lessons[b]['order']})   //get sorted keys

let sortedLessons={};

for(let key of keysSorted){
   sortedLessons[key]=users.lessons[key];
}

users.lessons=sortedLessons;
console.log(users)
Yogesh.Kathayat
  • 974
  • 7
  • 21
  • There is bad code formatting (specially the function in `sort`). The for loop not efficient when you can use builtin array functions (cf `reduce`). There is no explanations. In the end it's no easily readable and not efficient. – Mickael B. Jan 16 '20 at 12:08
  • Please see https://meta.stackoverflow.com/questions/392712/explaining-entirely-code-based-answers – Mickael B. Jan 16 '20 at 12:26