0

I have an array of objects like this:

// dishes: [
   {category: 'LEGUME', description: 'A'},
   {category: 'VEGETABLE', description: 'N'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'VEGETABLE', description: 'A'},
   {category: 'FISH', description: 'C'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'N'},
]

I'm sorting this array with this function:

const dishes = dishes.sort((a, b) => {
            if (a.category > b.category) return -1;
            if (a.category < b.category) return 1;
            return a.description.localeCompare(b.description);
          });

The output from above is like this:

// dishes: [
   {category: 'LEGUME', description: 'A'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'N'},
   {category: 'VEGETABLE', description: 'A'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'VEGETABLE', description: 'N'},
   {category: 'FISH', description: 'C'},
]

But now I want to force one of the categories to be the first one, let's say VEGETABLE, so the output should be:

// dishes: [
   {category: 'VEGETABLE', description: 'A'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'VEGETABLE', description: 'N'},
   {category: 'LEGUME', description: 'A'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'N'},
   {category: 'FISH', description: 'C'},
]

I've tried a bunch of solutions from other questions but none worked, any suggestions? is it possible?

Thanks in advance.

[UPDATED]: my final solution, thanks to @Andrew Parks:

dishes.sort((a, b) =>
    +(b.category === "VEGETABLE") -
    +(a.category === "VEGETABLE") ||
    a.category.localeCompare(b.category) ||
    a.description.localeCompare(b.description)
);

4 Answers 4

2

The neatest way is this:

const dishes = [
   {category: 'LEGUME', description: 'A'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'FISH', description: 'C'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'N'},
];

const cmp = (a,b,c) => a[c].localeCompare(b[c]);
const cmpEq = (a,b,c,d) => (b[c]===d) - (a[c]===d);
dishes.sort((a,b) => 
  cmpEq(a,b, 'category', 'VEGETABLE') || 
  cmp(a,b, 'category') || 
  cmp(a,b, 'description')
);

console.log(dishes);

If you want any of the sorts to be in reverse order, just put a minus sign in front of the cmp().

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

Comments

1

You can concatenate both category and description when sorting, as follows:

const dishes = [
   {category: 'LEGUME', description: 'A'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'VEGETABLE', description: 'A'},
   {category: 'VEGETABLE', description: 'N'},
   {category: 'FISH', description: 'C'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'N'}
]

dishes.sort((a, b) => {
  if (a.category === 'VEGETABLE') return -1
  if (b.category === 'VEGETABLE') return 1
  return `${a.category}${a.description}`.localeCompare(`${b.category}${b.description}`);
});

console.log(dishes)
.as-console-wrapper { max-height:100% !important; top 0; }

2 Comments

thats nice!, but now VEGETABLE is not alphabetically sorted. How would I sort that category too?
Did you not indicate an exception for it? But now I want to force one of the categories to be the first one, let's say VEGETABLE, so the output should be:...
1

You can special case the VEGETABLE value in your sort function:

const dishes = [
   {category: 'LEGUME', description: 'A'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'VEGETABLE', description: 'A'},
   {category: 'VEGETABLE', description: 'N'},
   {category: 'FISH', description: 'C'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'N'}
]

dishes.sort((a, b) => {
  res = (b.category == 'VEGETABLE') - (a.category == 'VEGETABLE')
  if (res) return res
  res = a.category.localeCompare(b.category)
  if (res) return res
  return a.description.localeCompare(b.description);
});

console.log(dishes)
.as-console-wrapper { max-height:100% !important; top 0; }

Note that sort sorts the array inplace so you don't need to assign the result from it.

2 Comments

Same as PeterKA. The answer is ok, but now VEGETABLE is not alphabetically sorted. How would I sort that category too?
@ismaestro apologies for that. I got fixated on the fact that there was only one VEGETABLE entry. I've corrected the code, but I think you've already accepted the best answer.
0

First compare by the difference of whether the items are of VEGETABLE or not - proceed to the rest of the sort function only if that results in 0.

const dishes = [
   {category: 'LEGUME', description: 'A'},
   {category: 'VEGETABLE', description: 'B'},
   {category: 'VEGETABLE', description: 'A'},
   {category: 'VEGETABLE', description: 'N'},
   {category: 'FISH', description: 'C'},
   {category: 'LEGUME', description: 'E'},
   {category: 'LEGUME', description: 'B'},
   {category: 'LEGUME', description: 'N'},
];
dishes.sort((a, b) => {
  const vegResult = a.category === 'VEGETABLE' - b.category === 'VEGETABLE';
  if (vegResult) return vegResult;
  if (a.category > b.category) return -1;
  if (a.category < b.category) return 1;
  return a.description.localeCompare(b.description);
});
console.log(dishes);

1 Comment

Sorry your solution does not work. If I choose another category like FISH, to be the first one, and obviously I replace VEGETABLE for FISH, it does not work. In fact, a.category === 'VEGETABLE' - b.category === 'VEGETABLE' is always false.

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.