8

I have an array of objects. Out of each of these objects onle few of them have a property and I want to sort the array putting those objects at top which have that property.

Ex -

arr= [{key1: "obj1val1", key2 :"obj1val2"}, 
      {key2 :"obj2val2"}, 
      {key1: "obj3val3", key2 :"obj3val3"},
      {key2 :"obj4val1"},
      {key1: "obj5val1", key2 :"obj5val2"}
]

Sorted by key1

Expected Result - [{key1: "obj1val1", key2 :"obj1val2"}, 
                   {key1: "obj3val3", key2 :"obj3val3"},
                   {key1: "obj5val1", key2 :"obj5val2"}, 
                   {key2 :"obj2val2"}, 
                   {key2 :"obj4val1"}]

I have tried below approach-

sort : function(arr) {
              var copyArr = arr.slice();
              var newArr = [];
              for(var i=0; i<arr.length; i++){
                if(arr[i].key1){
                  newArr.push(arr[i]);
                    copyArr.splice(i, 1);
                }
              }
              Array.prototype.push.apply(newArr, copyArr);
              return newArr;
            }

Not exactly but I see discrepancy from the above approach. For a array bigger length, some of the objects which have key1 are not moved to top. Can this be done by internal sort method of javascript? If yes, how will the custom function compare ?

Can only support ES5 methods.

5
  • 2
    Don't use splice while you are iterating. Commented Sep 22, 2018 at 21:39
  • Do you actually want to sort them by comparing all of them with each other, or do you want to keep the order but move those with the property to the top? In the latter case, don't use sort. Commented Sep 22, 2018 at 21:40
  • @Bergi That is why I have copied the original array and spliced the copied array. I want to keep the order but move the property to top Commented Sep 22, 2018 at 21:41
  • Still, the indices of the other elements change when you splice out one element. Commented Sep 22, 2018 at 21:43
  • 1
    Just use var withProp = [], withoutProp = []; … if ("key1" in arr[i]) withProp.push(arr[i]); else withoutProp.push(arr[i]); …. Don't copy anything beforehand or try to splice from it during a loop. Commented Sep 22, 2018 at 21:44

4 Answers 4

16

Can this be done by internal sort method of javascript

Yes: Simply prefer the entry that has the property:

arr.sort(function(left, right) {
    return left.hasOwnProperty("key1") ? -1 : right.hasOwnProperty("key1") ? 1 : 0
});

Live Example:

var arr = [
    {key1: "obj1val1", key2 :"obj1val2"}, 
    {key2 :"obj2val2"}, 
    {key1: "obj3val3", key2 :"obj3val3"},
    {key2 :"obj4val1"},
    {key1: "obj5val1", key2 :"obj5val2"}
];
arr.sort(function(left, right) {
    return left.hasOwnProperty("key1") ? -1 : right.hasOwnProperty("key1") ? 1 : 0
});
console.log(arr);

If you also want to sort by that property's value:

arr.sort(function(left, right) {
    var leftHas = left.hasOwnProperty("key1");
    var rightHas = right.hasOwnProperty("key1");
    if (leftHas && rightHas) {
      return left.key1.localeCompare(right.key1);
    }
    return leftHas ? -1 : rightHas ? 1 : 0;
});

Live Example:

var arr = [
    {key1: "obj1val1", key2 :"obj1val2"}, 
    {key2 :"obj2val2"}, 
    {key1: "obj3val3", key2 :"obj3val3"},
    {key2 :"obj4val1"},
    {key1: "obj5val1", key2 :"obj5val2"}
];
arr.sort(function(left, right) {
    var leftHas = left.hasOwnProperty("key1");
    var rightHas = right.hasOwnProperty("key1");
    if (leftHas && rightHas) {
      return left.key1.localeCompare(right.key1);
    }
    return leftHas ? -1 : rightHas ? 1 : 0;
});
console.log(arr);

Sign up to request clarification or add additional context in comments.

3 Comments

Hi TJ..can you share an ES5 version of this answer?
@RahulB - Wow, second nature to use arrow functions. :-) Done.
Gosh, I did wrote this logic but messed up the return statements in the ternary. Neat solution. Should have reached SO a little earlier, wasted half of my sleeping time. Thanks TJ
1

Here is a working snippet that gives your requested result and is easily extended. It uses the native array sort.

arr = [{
    key1: "obj1val1",
    key2: "obj1val2"
  },
  {
    key2: "obj2val2"
  },
  {
    key1: "obj3val3",
    key2: "obj3val3"
  },
  {
    key2: "obj4val1"
  },
  {
    key1: "obj5val1",
    key2: "obj5val2"
  }
]

const sorted = arr.sort((a, b) => {
  const k1 = a.key1 === undefined ? 0 : 1
  const k2 = b.key1 === undefined ? 0 : 2
  return k2- k1
})
console.log(sorted)

Comments

0

A kind of janky way you can do it is:

arr.filter(obj => obj.hasOwnProperty('key1')).concat(arr.filter(obj => !obj.hasOwnProperty('key1')));

Comments

0

https://github.com/arraybrain/arraybrain

for complex array stuff, you can use it

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.