1

Here is an example

testWidgetOrderSort = [
        { "_id": "name", "order": 1 },
        { "_id": "is", "order": 2 },
        { "_id": "my", "order": 0 },
        { "_id": "oh I would be very first" },
        { "_id": "adam", "order": 3 }

      ]

Here for the the object { "_id": "oh I would be very first" } does not have the property order so it should come first. And then the rest of the objects should be sorted according to the property "order" So after sorting it should be,

 output= [ { _id: 'oh I would be very first' },
      { _id: 'my', order: 0 },
      { _id: 'name', order: 1 },
      { _id: 'is', order: 2 },
      { _id: 'adam', order: 3 } ]
Avelanche
  • 121
  • 2
  • 10
  • 1
    If a comes before b, return -1, if b comes before a, return 1, otherwise check additional cases (HINT: `if`/`else if`/`else` is a clear pattern to follow for this). – crashmstr Aug 19 '21 at 11:21
  • Have you tried writing your custom sort logic when [sorting your array](https://stackoverflow.com/questions/979256/sorting-an-array-of-objects-by-property-values)? What did you try and what didn't work? – David Aug 19 '21 at 11:23
  • 1
    Hint 2: if `order` is `undefined`, it comes before an `order` that is not undefined. – crashmstr Aug 19 '21 at 11:29
  • I wrote a logic to sort using order but for objects where order is missing it is adding them in the end. function compare_order(a, b) { // a should come before b in the sorted order if (a.order < b.order) { return -1; // a should come after b in the sorted order } else if (a.order > b.order) { return 1; // a and b are the same } else { return 0; } } – Avelanche Aug 19 '21 at 11:30
  • If you don't care about performance too much, just create two arrays one without `order` (arr1) property and one with items having `order` (arr2) property. Push the items of arr1 to finalArr, then sort the items in arr2 and push it to finalArr. – Utkarsh Dixit Aug 19 '21 at 11:36
  • @Avelanche I thought I was pretty clear, if `undefined` for `order` should come first, that should be your first check. Instead, you leave one or the other as "don't change the order" (undefined > 1 is false, 1 > undefined is false). – crashmstr Aug 19 '21 at 13:29
  • Also, put the code you've tried *in the body of the question* and not as a comment. – crashmstr Aug 19 '21 at 13:30
  • Does this answer your question? [Sort javascript array of objects by child properties (which may be missing)](//stackoverflow.com/q/29058568/90527) – outis Feb 03 '22 at 09:01

4 Answers4

5

Logic is basic array sorting logic.

  • If both a.order and b.order are defined return 1 or -1 depending on the largest value.
  • If either one of them is undefined return 1 or -1 depending on the defined value.
  • Please Note: The value 1 and -1 determines the relative position between the two nodes. Returning 1 places a after b and -1 places a before b.

const testWidgetOrderSort = [
  { "_id": "name", "order": 1 },
  { "_id": "is", "order": 2 },
  { "_id": "my", "order": 0 },
  { "_id": "oh I would be very first" },
  { "_id": "adam", "order": 3 }
];
const output = testWidgetOrderSort.sort((a, b) => {
  if( a.order !== undefined && b.order !== undefined ) {
    return a.order > b.order ? 1 : -1;
  } else {
    return a.order !== undefined ? 1 : -1
  }
});
console.log(output);
Nitheesh
  • 19,238
  • 3
  • 22
  • 49
  • The [comma](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator) in that `if` does not do what you think it does. – crashmstr Aug 19 '21 at 13:26
  • @crashmstr that was actually a typo and amajor bug. Thanks for pointing it out. I have fixed that in my code. – Nitheesh Aug 19 '21 at 13:42
1

I came up with something like this:

const test = [
  { "_id": "name", "order": 1 },
  { "_id": "is", "order": 2 },
  { "_id": "my", "order": 0 },
  { "_id": "oh I would be very first" },
  { "_id": "adam", "order": 3 }
];

const x = test.sort((a, b) => {
  const [STAY, SWAP] = [-1, 1];
  if (!a.hasOwnProperty('order')) { return STAY; }
  if (!b.hasOwnProperty('order')) { return SWAP; }
  return a.order - b.order;
});

console.log(x);
Habebit
  • 957
  • 6
  • 23
0

You just have to pass the custom comparator function

if (!("order" in a)) return -1;
if (!("order" in b)) return 1;
else return a.order - b.order;

1) return -1 if property order doesn't exist in a.

2) return 1 if property order doesn't exist in b.

3) if both the object has order property then just sort in ascending order.

const arr = [
  { _id: "name", order: 1 },
  { _id: "is", order: 2 },
  { _id: "my", order: 0 },
  { _id: "oh I would be very first" },
  { _id: "adam", order: 3 },
];

const result = arr.sort((a, b) => {
  if (!("order" in a)) return -1;
  if (!("order" in b)) return 1;
  else return a.order - b.order;
});

console.log(result);
DecPK
  • 24,537
  • 6
  • 26
  • 42
  • Not an issue here, but usually using `Object.protoype.hasOwnProperty` instead of `key in` is the best practice to avoid searching through prototype chaining, – Utkarsh Dixit Aug 19 '21 at 11:46
0

If you don't care about the performance too much, the below should be fine,

const testWidgetOrderSort = [
  { "_id": "name", "order": 1 },
  { "_id": "is", "order": 2 },
  { "_id": "my", "order": 0 },
  { "_id": "oh I would be very first" },
  { "_id": "adam", "order": 3 }

];

const finalArr = testWidgetOrderSort.filter(a => typeof a.order === "undefined");

const sortedArrWithOrderItems = testWidgetOrderSort.filter(a => typeof a.order !== "undefined").sort((a,b) => (a.order > b.order ? 1 : -1));

finalArr.push(...sortedArrWithOrderItems);

console.log(finalArr);

Note: Personally I would recommend going with @Nitheesh or @decpk solution, it is more clean and performance wise better. My solution is just to give another solution for the problem

Utkarsh Dixit
  • 4,267
  • 3
  • 15
  • 38