0

How would I sort the first array into a final product that reflects the second array, please?

(I'm sorting first by Category but then I'm sorting by Subcategory while pushing 'Other' to the end of the Category's section.)

Input:

var unsorted = [
    {category: 'Computer', subcategory: 'Laptop'},
    {category: 'Computer', subcategory: 'Other'},
    {category: 'Computer', subcategory: 'Desktop'},
    {category: 'Network Device', subcategory: 'Gateway'},
    {category: 'Computer', subcategory: 'Virtual'},
    {category: 'Network Device', subcategory: 'Other'}
]

Desired Output:

var sorted = [
    {category: 'Computer', subcategory: 'Desktop'},
    {category: 'Computer', subcategory: 'Laptop'},
    {category: 'Computer', subcategory: 'Virtual'},
    {category: 'Computer', subcategory: 'Other'},
    {category: 'Network Device', subcategory: 'Gateway'},
    {category: 'Network Device', subcategory: 'Other'}
]

I've seen great answers for double-sorting and for pushing certain values to the end, but I haven't seen an answer for doing both at once in this way.

Thank you for your time!

Kind Regards, Joseph

Joseph316
  • 69
  • 6

2 Answers2

2

You need a sorting function that...

  • compares categories (with localeCompare()) first, returns result immediately if it's not 0 (meaning categories are different)
  • checks subcategory of the first argument, returns 1 (meaning a > b) if it's "Other"
  • checks subcategory of the second argument, returns -1 (meaning a < b) if it's "Other"
  • if all previous checks fail, returns result of subcategories comparison

Here's one possible way to implement it:

var unsorted = [
    {category: 'Computer', subcategory: 'Laptop'},
    {category: 'Computer', subcategory: 'Other'},
    {category: 'Computer', subcategory: 'Desktop'},
    {category: 'Network Device', subcategory: 'Gateway'},
    {category: 'Computer', subcategory: 'Virtual'},
    {category: 'Network Device', subcategory: 'Other'}
]

const sorted = unsorted.slice() // creating a copy to avoid mutating the original
.sort((
  {category: ca, subcategory: sca}, 
  {category: cb, subcategory: scb}
) => ca.localeCompare(cb) || 
  (sca === 'Other' ? 1 : scb === 'Other' ? -1 : sca.localeCompare(scb)));

console.log(sorted);

In this function ca and sca are values (assigned through so-called "parameter fields unpacking") of category and subcategory of the first param of sorting function, cb and scb - the same fields of the second param.

raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • Wow, this answer is great! I got my answer. AND I learned about "Unpacking fields from objects passed as a function parameter" (Is it just me, or is this feature's syntax bizarre?) Thank you for giving an advanced answer while providing enough context to begin to understand it! It's frustrating when the context is missing from an advanced answer, but your context was great! – Joseph316 Jul 06 '21 at 20:37
1

Here is another variation, using an object o to "push" the subcategory "Other" to the end of the alphabet ("zzzzzz"):

var unsorted = [
    {category: 'Computer', subcategory: 'Laptop'},
    {category: 'Computer', subcategory: 'Other'},
    {category: 'Computer', subcategory: 'Desktop'},
    {category: 'Network Device', subcategory: 'Gateway'},
    {category: 'Computer', subcategory: 'Virtual'},
    {category: 'Network Device', subcategory: 'Other'}
], o={Other:"zzzzzz"};

sorted=unsorted.slice(0).sort((
  {category: ca, subcategory: sca}, 
  {category: cb, subcategory: scb}
) => ca.localeCompare(cb) || (o[sca]||sca).localeCompare(o[scb]||scb));

console.log(sorted);
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43