skip to Main Content

Let’s say I have this array:

const services = [
    { id: 100, priority: 'Y', count: 300, payout: '30', id_region: 137 },
    { id: 101, priority: 'N', count: 200, payout: '40', id_region: 153 },
    { id: 102, priority: 'Y', count: 400, payout: '30', id_region: 137 },
    { id: 103, priority: 'Y', count: 500, payout: '50', id_region: 153 },
    { id: 104, priority: 'Y', count: 800, payout: '80', id_region: 222 }
];

And this global variable:

var regionsFound = ['153'];

I want to sort:

  • first the id_region if that appears in regionsFound
  • then priority ‘Y’ first
  • then highest payout
  • then the id_region if that doesn’t appear in regionsFound
  • then count

Here’s my code:

services.sort((a, b) => {
 if (regionsFound.indexOf(a.id_region.toString()) >= 0 && regionsFound.indexOf(b.id_region.toString()) >= 0){
    if (a.priority == 'Y' && b.priority == 'N'){
        return -1;
    } else if (a.priority == 'N' && b.priority == 'Y'){
        return 1;
    }
    return b.payout - a.payout;    
 } else if (regionsFound.indexOf(a.id_region.toString()) >= 0 && regionsFound.indexOf(b.id_region.toString()) < 0){
    return -1;
 } else {
    return b.count - a.count; 
 }
});

So the result should be:

const services = [
    { id: 103, priority: 'Y', count: 500, payout: '50', id_region: 153 },
    { id: 101, priority: 'N', count: 200, payout: '40', id_region: 153 },
    { id: 104, priority: 'Y', count: 800, payout: '80', id_region: 222 },
    { id: 102, priority: 'Y', count: 400, payout: '30', id_region: 137 },
    { id: 100, priority: 'Y', count: 300, payout: '30', id_region: 137 }
];

I don’t know where’s the error.

HERE’S THE FINAL CODE AFTER THE COMMENTS:

services.sort((a, b) => {
    let aInRegionsFound = regionsFound.includes(String(a.id_region));
    let bInRegionsFound = regionsFound.includes(String(b.id_region));

    if (aInRegionsFound && !bInRegionsFound){
        return -1;
    } else if (!aInRegionsFound && bInRegionsFound){
        return 1;
    } else if (!aInRegionsFound && !bInRegionsFound){
        return b.count - a.count; 
    } else {
        if (a.priority == 'Y' && b.priority == 'N'){
            return -1;
        } else if (a.priority == 'N' && b.priority == 'Y'){
            return 1;
        }
        return parseFloat(b.payout) - parseFloat(a.payout);
    }
});

4

Answers


  1. You almost had it, you just need to convert payout values to numerical numbers first before you can sort them correctly.

    I also changed indexof for include to have a cleaner code

    const services = [
        { id: 100, priority: 'Y', count: 300, payout: '30', id_region: 137 },
        { id: 101, priority: 'N', count: 200, payout: '40', id_region: 153 },
        { id: 102, priority: 'Y', count: 400, payout: '30', id_region: 137 },
        { id: 103, priority: 'Y', count: 500, payout: '50', id_region: 153 },
        { id: 104, priority: 'Y', count: 800, payout: '80', id_region: 222 }
    ];
    
    var regionsFound = ['153'];
    
    services.sort((a, b) => {
        const aRegionFound = regionsFound.includes(a.id_region.toString());
        const bRegionFound = regionsFound.includes(b.id_region.toString());
    
        if (aRegionFound === bRegionFound) {
            if (a.priority === 'Y' && b.priority === 'N') {
                return -1;
            } else if (a.priority === 'N' && b.priority === 'Y') {
                return 1;
            }
            return parseInt(b.payout) - parseInt(a.payout);
        } else if (aRegionFound && !bRegionFound) {
            return -1;
        } else if (!aRegionFound && bRegionFound) {
            return 1;
        } else {
            return b.count - a.count;
        }
    });
    
    console.log(services)
    Login or Signup to reply.
  2. I think you’ll save yourself a lot of headache if you don’t nest your if statements. Something like this should do the trick:

    const services = [
        { id: 100, priority: 'Y', count: 300, payout: '30', id_region: 137 },
        { id: 101, priority: 'N', count: 200, payout: '40', id_region: 153 },
        { id: 102, priority: 'Y', count: 400, payout: '30', id_region: 137 },
        { id: 103, priority: 'Y', count: 500, payout: '50', id_region: 153 },
        { id: 104, priority: 'Y', count: 800, payout: '80', id_region: 222 }
    ];
    var regionsFound = ['153'];
    
    services.sort((a, b) => {
        // first the id_region if that appears in regionsFound
        const aInRegionsFound = regionsFound.includes(String(a.id_region));
        const bInRegionsFound = regionsFound.includes(String(b.id_region));
    
        if (aInRegionsFound !== bInRegionsFound) return aInRegionsFound ? -1 : 1;
    
        // then priority 'Y' first
        if (a.priority !== b.priority) return a.priority === 'Y' ? -1 : 1;
    
        // then highest payout
        if (a.payout !== b.payout) return Number(a.payout) > Number(b.payout) ? -1 : 1;
    
        // then the id_region if that doesn't appear in regionsFound
        if (a.id_region !== b.id_region) return a.id_region > b.id_region ? -1 : 1;
    
        // then count
        return b.count - a.count
    });
    
    Login or Signup to reply.
  3. You can chain subtract operations with || given that - operator converts its operands to numbers.

    For the region lookup I recommend use Set.

    It’s not clear how id_region is sorted, just swap a and b if needed.

    const services = [
        { id: 100, priority: 'Y', count: 300, payout: '30', id_region: 137 },
        { id: 101, priority: 'N', count: 200, payout: '40', id_region: 153 },
        { id: 102, priority: 'Y', count: 400, payout: '30', id_region: 137 },
        { id: 103, priority: 'Y', count: 500, payout: '50', id_region: 153 },
        { id: 104, priority: 'Y', count: 800, payout: '80', id_region: 222 }
    ];
    var regionsFound = ['153'];
    
    const regions = new Set(regionsFound.map(id => +id));
    
    services.sort((a, b) => 
      regions.has(b.id_region) - regions.has(a.id_region) ||
      (b.priority === 'Y') - (a.priority === 'Y') ||
      b.payout - a.payout || 
      a.id_region - b.id_region ||
      b.count - a.count
    )
          
    services.forEach(s => console.log(JSON.stringify(s)));
    Login or Signup to reply.
  4. Use sort function for multiple sort criteria based on index value like this

    const services = [
      { id: 100, priority: "Y", count: 300, payout: "30", id_region: 137 },
      { id: 101, priority: "N", count: 200, payout: "40", id_region: 153 },
      { id: 102, priority: "Y", count: 400, payout: "30", id_region: 137 },
      { id: 103, priority: "Y", count: 500, payout: "50", id_region: 153 },
      { id: 104, priority: "Y", count: 800, payout: "80", id_region: 222 },
    ];
    
    const sortCriteria = [
      { field: "id_region", found: ["153"] },
      { field: "priority", found: ["Y", "N"] },
      { field: "payout", desc: true },
      { field: "count", asc: true },
    ];
    
    const sort = (list, sCriteria) => {
      sCriteria = sCriteria.reverse();
      return list.sort((a, b) => {
        return sCriteria.reduce((init, criteria) => {
          const { field, found, asc, desc } = criteria;
          const x = a[field];
          const y = b[field];
          if (found && found.length) {
            let xIdx = found.indexOf(x.toString());
            let yIdx = found.indexOf(y.toString());
            xIdx = xIdx == -1 ? found.length : xIdx;
            yIdx = yIdx == -1 ? found.length : yIdx;
            init = xIdx <= yIdx ? -1 : 1;
          } else if (asc) {
            init = x <= y ? -1 : 1;
          } else if (desc) {
            init = x >= y ? -1 : 1;
          }
          return init;
        }, 1);
      });
    };
    const sortList = sort(services, sortCriteria);
    sortList.forEach((item) => console.log(JSON.stringify(item)));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search