Sara Ree
Sara Ree

Reputation: 3543

sort array of objects based on two layers

I want to sort this array of objects where each object should be ascending in each unit and units should be sorted ascending based on order too:

const userCards  = [
  {
    unit: 5,
    order: 1,
  },

  {
    unit: 5,
    order: 3,
  },
  {
    unit: 5,
    order: 2,
  },
  {
    unit: 6,
    order: 2,
  },
  {
    unit: 6,
    order: 1,
  },
  {
    unit: 6,
    order: 3,
  },
  {
    unit: 7,
    order: 1,
  },
  {
    unit: 4,
    order: 2,
  },
  {
    unit: 1,
    order: 1,
  },
  {
    unit: 1,
    order: 2,
  },
  {
    unit: 1,
    order: 3,
  },
  {
    unit: 1,
    order: 4,
  },
  {
    unit: 3,
    order: 2,
  }
]

function compare(a, b) {
  if (a.unit > b.unit && a.order > b.order) return 1;
  if (a.unit < b.unit) return -1;
  return 0;
}
const res = userCards.sort(compare);

console.log(res)

For instance the desired result would be :

{
   unit: 5,
   order: 1,
},

{
   unit: 5,
   order: 2,
},

{
   unit: 6,
   order: 1,
},

{
   unit: 6,
   order: 2,
},

As you see so far this is not happening!

How can I fix this?

Upvotes: 1

Views: 77

Answers (3)

RenaudC5
RenaudC5

Reputation: 3829

A B a.unit > b.unit && a.order > b.order a.unit > b.unit value returned
{unit: 5, order: 3} {unit: 4, order: 1} True 1 <-- meaning A > B
{unit: 5, order: 3} {unit: 5, order: 1} False False 0 <-- meaning same value
{unit: 4, order: 1} {unit: 3, order: 2} False True -1 <-- meaning A > B
{unit: 1, order: 1} {unit: 3, order: 2} False True 0 <-- meaning same value

As you can see on this example, your condition does not work as you want since it has return 0 2 times.


Reading the Array#sort documentation the return of the sort function is the following

compareFunction(a, b) return value sort order
> 0 sort b before a
< 0 sort a before b
=== 0 keep original order of a and b

So here you can just do the following :

  • if the unit are equals, return the dufference between the orders
  • else return the difference between the units
function compare(a, b) {
  if(a.unit === b.unit) return a.order - b.order 
  else return a.unit - b.unit
}

Or with one line using ternary

function compare = (a, b) => a.unit === b.unit ? a.order - b.order : a.unit - b.unit

Working example

const userCards  = [
  {
    unit: 5,
    order: 1,
  },

  {
    unit: 5,
    order: 3,
  },
  {
    unit: 5,
    order: 2,
  },
  {
    unit: 6,
    order: 2,
  },
  {
    unit: 6,
    order: 1,
  },
  {
    unit: 6,
    order: 3,
  },
  {
    unit: 7,
    order: 1,
  },
  {
    unit: 4,
    order: 2,
  },
  {
    unit: 1,
    order: 1,
  },
  {
    unit: 1,
    order: 2,
  },
  {
    unit: 1,
    order: 3,
  },
  {
    unit: 1,
    order: 4,
  },
  {
    unit: 3,
    order: 2,
  }
]

const compare = (a, b) => a.unit === b.unit ? a.order - b.order : a.unit - b.unit
const res = userCards.sort(compare);

console.log(JSON.stringify(res))

Upvotes: 0

zer00ne
zer00ne

Reputation: 43853

Details are commented in example below

const userCards = [{
    unit: 5,
    order: 1,
  },
  {
    unit: 5,
    order: 2,
  },
  {
    unit: 6,
    order: 2,
  },
  {
    unit: 6,
    order: 1,
  },
  {
    unit: 6,
    order: 3,
  },
  {
    unit: 7,
    order: 1,
  },
  {
    unit: 5,
    order: 3,
  },
  {
    unit: 4,
    order: 2,
  },
  {
    unit: 1,
    order: 1,
  },
  {
    unit: 1,
    order: 2,
  },
  {
    unit: 1,
    order: 3,
  },
  {
    unit: 1,
    order: 4,
  },
  {
    unit: 3,
    order: 2,
  }
];

/*
Create a reference object array that stores the keys needed to be in order
*/
let orderKey = [{
  key: 'unit'
}, {
  key: 'order'
}];

// Pass both object arrays
function compare(objArray, sortOrder) {
  // Start with .sort()
  return objArray.sort((a, b) => {
    // Define counter and ternary value initial defaults
    let i = 0,
      result = 0;
    /*
    As long as counter is less than sortOrder total AND ternary is 0
    ...Define A as previous value of current key...
    ...Define B as current value of current key...
    ...If A is less than B return -1 (A and B stay)...
    ...if A is greater than B return 1 (A and B swap)...
    ...else return 0 (A and B stay)...
    ...increment counter...
    */
    while (i < sortOrder.length && result === 0) {
      let A = a[sortOrder[i].key],
        B = b[sortOrder[i].key];
      result = A < B ? -1 : A > B ? 1 : 0;
      i++;
    }
    return result;
  });
}

console.log(JSON.stringify(compare(userCards, orderKey)));

Upvotes: 0

Tam&#225;s Katona
Tam&#225;s Katona

Reputation: 833

function compare(a, b) {
  if (a.unit == b.unit) {
        return a.order - b.order;
    }

  return a.unit - b.unit;
}

Upvotes: 2

Related Questions