Home > Blockchain >  How to Sort Nested Array By Multiple Value in JavaScript
How to Sort Nested Array By Multiple Value in JavaScript

Time:11-26

I need to sort nested array while sorting order and the sorting key will be dynamic. I am using the query but it work only on plain text. Sample Data:

[
   {
      "modelId":1,
      "modelCode":"model1",
      "price":[
         {
            "PRICE_CODE1":225.01
         },
         {
            "PRICE_CODE2":247.68
         },
         {
            "PRICE_CODE3":298.0
         }
      ]
   },
   {
      "modelId":2,
      "modelCode":"model2",
      "price":[
         {
            "PRICE_CODE1":100.01
         },
         {
            "PRICE_CODE2":200.68
         },
         {
            "PRICE_CODE3":300.0
         }
      ]
   }
]

Expected Output:

[
   {
      "modelId":2,
      "modelCode":"model2",
      "price":[
         {
            "PRICE_CODE1":100.01
         },
         {
            "PRICE_CODE2":200.68
         },
         {
            "PRICE_CODE3":300.0
         }
      ]
   },
   {
      "modelId":1,
      "modelCode":"model1",
      "price":[
         {
            "PRICE_CODE1":225.01
         },
         {
            "PRICE_CODE2":247.68
         },
         {
            "PRICE_CODE3":298.0
         }
      ]
   }
]

as per the above example sorting is PRICE_CODE1, modelCode with ascending order. I am using the below query-

function sortByMultipleKey(keys) {
    return function(a, b) {
        if (keys.length == 0) return 0; // force to equal if keys run out
        key = keys[0]; // take out the first key
        if (a[key] < b[key]) return -1; // will be 1 if DESC
        else if (a[key] > b[key]) return 1; // will be -1 if DESC
        else return sortByMultipleKey(keys.slice(1))(a, b);
    }
}
arr.sort(sortByMultipleKey(['PRICE_CODE1','modelCode']))

above query is working for plain arrays not for arrays of arrays because in example price is array. How to achieve this?

CodePudding user response:

Warning: This would work for the price array structure you have but not for modelCode as sort key.

const data = [
   {
      "modelId":2,
      "modelCode":"model2",
      "price":[
         {
            "PRICE_CODE1":100.01
         },
         {
            "PRICE_CODE2":200.68
         },
         {
            "PRICE_CODE3":300.0
         }
      ]
   },
   {
      "modelId":1,
      "modelCode":"model1",
      "price":[
         {
            "PRICE_CODE1":225.01
         },
         {
            "PRICE_CODE2":247.68
         },
         {
            "PRICE_CODE3":298.0
         }
      ]
   }
]

function sortData(sortKeys = []) {
  data.sort((a,b) => {
    for (let sortKey of sortKeys) {
      const priceObjA = a.price.find(x => sortKey in x);
      const priceObjB = b.price.find(x => sortKey in x);
      const priceA = priceObjA && priceObjA[sortKey] || 0;
      const priceB = priceObjB && priceObjB[sortKey] || 0;
      const result = priceA - priceB;
      if (result !== 0) {
        return result;
      }
    }
    // fallback for equality
    return 0;
  })
}


sortData(['PRICE_CODE1']);
console.log(JSON.stringify(data,null,2));

sortData(['PRICE_CODE2']);
console.log(JSON.stringify(data,null,2));

sortData(['PRICE_CODE3']);
console.log(JSON.stringify(data,null,2));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

arr.sort(sortByMultipleKey(['PRICE_CODE1','modelCode']))

Your sortByMultipleKey takes a list of keys, each of which describe one key. That can't describe the PRICE_CODE1 field of an object under prices.

You're essentially trying to come up with a syntax to describe arbitrary location in hierarchical data.

Instead of doing that, Use Javascript itself to define how to find the next comparison field! pass functions that can resolve the fields and iterate over those.

Below, I will define 2 functions. The first will extract the first PRICE_CODE1 from the elements of prices.

  function(d) {
    for (i = 0; i < d.price.length; d  ) {
      if ("PRICE_CODE1" in d.price[i]) {
        return d.price[i].PRICE_CODE1
      }
    }
    return undefined
  }

The one for modelCode is simpler:

  function(d) {
    return d.modelCode
  }

I also add a 3rd model with the same PRICE_CODE1 so that modelCode would also be relevant.

function sortByMultiple(field_funcs) {
  return function(a, b) {
    for (i = 0; i < field_funcs.length; i  ) {
      fa = field_funcs[i](a)
      fb = field_funcs[i](b)
      console.log("Comparing "   fa   " and "   fb)
      if (fa < fb) return -1;
      if (fa > fb) return 1;
      if (i   1 == field_funcs.length) return 0
    }
  }
}
var data = [{
    "modelId": 2,
    "modelCode": "model2",
    "price": [{
        "PRICE_CODE1": 100.01
      },
      {
        "PRICE_CODE2": 200.68
      },
      {
        "PRICE_CODE3": 300.0
      }
    ]
  },
  {
    "modelId": 1,
    "modelCode": "model1",
    "price": [{
        "PRICE_CODE1": 225.01
      },
      {
        "PRICE_CODE2": 247.68
      },
      {
        "PRICE_CODE3": 298.0
      }
    ]
  },
  {
    "modelId": 3,
    "modelCode": "model3",
    "price": [{
        "PRICE_CODE1": 225.01
      },
      {
        "PRICE_CODE2": 247.68
      },
      {
        "PRICE_CODE3": 298.0
      }
    ]
  }
]

data.sort(sortByMultiple([
  function(d) {
    for (i = 0; i < d.price.length; d  ) {
      if ("PRICE_CODE1" in d.price[i]) {
        return d.price[i].PRICE_CODE1
      }
    }
    return undefined
  },
  function(d) {
    return d.modelCode
  }
]))
console.log(data)
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You can use lodash library:

_.orderBy( data, [c => c.price[0].PRICE_CODE1, "modelCode"], ["asc", "asc"]);
  • Related