3

CASE 1:

let items = [
  { name: "Edward", value: 21 },
  { name: "Shane", value: 37 },
  { name: "Daniel", value: 45 },
  { name: "Daniel", value: -12 },
  { name: "Magnetic", value: 13 },
  { name: "Magnetic", value: 37 },
];

items.sort(function (a, b) {
  if (a.name<b.name) {
    return -1;
  }
  if (a.name>b.name) {
    return 1;
  }
  // names must be equal
  return 0;
});

console.log(items);

CASE 2:

let items = [
  { name: "Edward", value: 21 },
  { name: "Shane", value: 37 },
  { name: "Daniel", value: 45 },
  { name: "Daniel", value: -12 },
  { name: "Magnetic", value: 13 },
  { name: "Magnetic", value: 37 },
];

items.sort(function (a, b) {
  if (a.name<b.name) {
    return -1;
  }
  if (a.name>b.name) {
    return 1;
  }
  // no case for equal names
});

console.log(items);

CASE 3:

items.sort(function (a, b) {
  return a.name < b.name ? -1 : 1;
});

All three return the following

[
  { name: 'Daniel', value: 45 },
  { name: 'Daniel', value: -12 },
  { name: 'Edward', value: 21 },
  { name: 'Magnetic', value: 13 },
  { name: 'Magnetic', value: 37 },
  { name: 'Shane', value: 37 }
]

All the above mentioned snippets return the same result, but there's definitely some example where all these return different results (Which I don't know). I wanted to know what happens when there's no return condition for the names being equal.

UPDATE: I've added a case 3 to the original question, actually case 1 and case 2 behave similarly because case 2 returns undefined when names are equal. But in case 3 where I use ternary operator it doesn't return undefined but still the answer remains the same. HOW?

  • _"but there's definitely some example where both these return different results"_ - Don't you think those examples would be more meaningful for this question? – Andreas Oct 02 '20 at 14:14
  • 2
    In this case the result will be the same. If the compare function returns `undefined`, which converts to `NaN` when convert to a number, then that value is converted to `0`. https://www.ecma-international.org/ecma-262/10.0/#sec-sortcompare – Felix Kling Oct 02 '20 at 14:17
  • 1
    `This I can simplify to the below ternary expression: nameA < nameB ? -1 : 1` that's not correct. the corrct ternary expression for that function is `nameA < nameB ? -1 : nameA > nameB ? 1 : undefined`. Check out [localeCompare](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) – Thomas Oct 02 '20 at 14:19
  • Suggested reading on sorting: [Sorting in JavaScript: Shouldn't returning a boolean be enough for a comparison function?](https://stackoverflow.com/q/24080785) – VLAZ Oct 02 '20 at 14:20
  • "*This I can simplify to the below ternary expression // nameA < nameB ? -1 : 1*" why do you want to simplify it to use the conditional operator? Why not simplify it further to not having to compare them yourself at all? You can just let JS handle it with `nameA.localeCompare(nameB)` – VLAZ Oct 02 '20 at 14:21
  • @Andreas I couldn't find any, actually I am looking for such examples myself. –  Oct 02 '20 at 14:28
  • @VLAZ This is just an example I want to extend this idea further so I wish to do it using .sort() only –  Oct 02 '20 at 14:29
  • @Thomas Ya my bad, but using ternary operator also returns the same result why? I've updated my question –  Oct 02 '20 at 14:35
  • 1
    You are comparing objects..... does not make any sense. – epascarello Oct 02 '20 at 14:43
  • 2
    @SomShekharMukherjee "*but using ternary operator also returns the same result why?*" I *heavily suggest* you read the link I posted. What you've done is conflated two of the states (equality and bigger than) into one (bigger than). You can expect odd sorting at times that is dependent on the browser and the dataset you use. So, it's going to be incorrect in some cases, but it's going to be very hard to find out which ones and why. – VLAZ Oct 02 '20 at 14:43
  • @SomShekharMukherjee No it does not, not reliably, not stable. Just read the first paragraph in the [accepted answer from the Questioin VLAZ linked](https://stackoverflow.com/a/24080786/6567275). The consequence of this is, that you may come across a list/browser/comparator-function combination where you sort the same list over and over with the same function and the entries will jump around (with your approach) – Thomas Oct 02 '20 at 14:45
  • @epascarello Sorry that was a typo, I wanted to compare names within the objects –  Oct 02 '20 at 15:02
  • @VLAZ Okay thanks will definitely read that. So, it can be solved using `<=` instead of just `=`. Right?? –  Oct 02 '20 at 15:05
  • @Thomas Thanks will read that! So using `<=` will solve my problem, right? –  Oct 02 '20 at 15:06

2 Answers2

1

The main issue with your code is you are comparing Objects which makes no sense. So you should do sorting on a property in the object. Look at what the tests do.

var a = { foo: 1 };
var b = { foo: 2 };

console.log("a > b", a > b);
console.log("a > b", a < b);
console.log("a == b", a == b);

So in your sort you are literally have the same result in each check. It makes no sense. You need to look at the data in the object. You should be checking for 3 states 1) SAME, 2) Greater, and 3) Less Than.

When you do not return correct values for each state, you may run into browser sorting items differently each time. In your case you are not returning anything when it is equal and that will be seen as undefined and that us a falsely value so should probably be 0 which is equal. When you are just returning 1 and -1, you are making the browser do a lot more work since it is getting different values every time is makes a comparison. That will cause sort order to differ and can make it take extra long since it makes extra calculations.

let items = [
  { name: "Car", value: 100 },
  { name: "Apple", value: 21 },
  { name: "Car", value: 13 },
  { name: "Far", value: 37 },
  { name: "Apple", value: 10 },
  { name: "Bar", value: 45 }
];


items.sort( function (a, b) {

  // if names are equal lets sort on value
  if (a.name === b.name) {
    if (a.value === b.value) {
      return 0;
    } else if (a.value > b.value) {
      return 1;
    } else {
      return -1;
    }
  }
  else if (a.name > b.name) {
    return 1;
  }
  else {
    return -1;
  }
});

console.log(items);

Code cleaned up

let items = [
  { name: "Car", value: 100 },
  { name: "Apple", value: 21 },
  { name: "Car", value: 13 },
  { name: "Far", value: 37 },
  { name: "Apple", value: 10 },
  { name: "Bar", value: 45 }
];

items.sort( function (a, b) {

  // if names are equal lets sort on value
  if (a.name === b.name) {
    if (a.value === b.value) {
      return 0;
    } else {
      return (a.value > b.value) ? 1 : -1;
    }
  } else {
    return a.name.localeCompare(b.name);
  }
});

console.log(items);
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • 1
    The final code can be made a lot shorter via `(a, b) => a.name.localeCompare(b.name) || (a.value - b.value)` – VLAZ Oct 02 '20 at 15:09
  • Comparing objects was a typo, I just updated my question, so if you update your answer I can accept your answer. –  Oct 02 '20 at 15:11
0

If you don't specify a return for a function it returns undefined

function f() {
  // no return specified
}

let x = f(); // undefined

Now undefined is a falsy value, i.e. it can be coerced to false or 0. So although you're not explicitly returning 0, you're returning undefined which can sometimes work like 0

Another way to write this would be

items.sort(function (a, b) {
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }
  
  // return "undefined" if it gets to this line
});
Shadab
  • 1,297
  • 6
  • 9
  • 1
    To be more precise -> [22.1.3.27.1 Runtime Semantics: `SortCompare ( x, y )`](https://tc39.es/ecma262/#sec-sortcompare): `.sort()` calls `ToNumber()` on the result of the compare function (step 4a). In the case of `undefined` `ToNumber()` will return `NaN` which will be replaced with `+0` (step 4b) – Andreas Oct 02 '20 at 14:20
  • Okay but what if I use a ternary operator, in that case there's no undefined, but still it gives the same result, how? I've updated my question –  Oct 02 '20 at 14:34