Search code examples
javascriptarrayssortingcomparelookup

How to sort an array of objects on the basis of properties which are provided by another array of objects?


I have been working around for sorting an array of objects according to a property that doesn't exist in that array. I had my first array like

const scores = [
    {
        "scoreDefinitionName": "_mo45",
        "score": 0,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573564",
            "globalId": null,
            "version": 0
        }
    },
    {
        "scoreDefinitionName": "_sc45",
        "score": 0,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573568",
            "globalId": null,
            "version": 0
        }
    },
    {
        "scoreDefinitionName": "_ua45",
        "score": 0,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573572",
            "globalId": null,
            "version": 0
        }
    },
    {
        "scoreDefinitionName": "KFT",
        "score": 1,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573576",
            "globalId": null,
            "version": 0
        }
    },
    {
        "scoreDefinitionName": "LFT",
        "score": 1,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573580",
            "globalId": null,
            "version": 0
        }
    },
    {
        "scoreDefinitionName": "dummy",
        "score": 1,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573584",
            "globalId": null,
            "version": 0
        }
    },
    {
        "scoreDefinitionName": "Score",
        "score": 0.32,
        "scoreDefinitionId": {
            "objectType": "ScoreDefinition",
            "idValue": "573588",
            "globalId": null,
            "version": 0
        }
    }
]

and second array is like

[
  {
    variableName: "KFT",
    variable: "KFT",
    sequence: 1,
    variableDetail: {
      displayName: ""
    },
  },
  {
    variableName: "LFT",
    variable: "LFT",
    sequence: 3,
    variableDetail: {
      displayName: ""
    },
  },
  {
    variableName: "Dummy",
    variable: "dummy",
    sequence: 2,
    variableDetail: {
      displayName: ""
    }
  }
];

So bascially what I want to do is to sort the first array scores according to the sequence of that object which matches with object in second array varibles when the name property matches.

One work around I found is to first push the sequence property of variables array in the scores array and then sort according to that But I believe it can be optimised more. Any other way to make it more optimise ?


Solution

  • Presented below is one possible way to achieve the desired objective, with the assumption that the scores array needs to be sorted based on the sequence prop on the variables array (& not on the order in which the variables array is populated). In other words, the desired sort-order is KFT, Dummy, LFT, which is as per the sequence being 1, 2, 3; and it is not KFT, LFT, Dummy whose corresponding sequence is 1, 3, 2.

    Code Snippet

    // method to sort using custom logic (without mutating the input array)
    const mySort = (arr, ord) => (
      structuredClone(arr)                  // deep-clone to avoid mutating parameter array
      .sort(
        (
          {scoreDefinitionName: sdA},       // de-structure to access "scoreDefinitionName"
          {scoreDefinitionName: sdB}        // of both 'a' and 'b'
        ) => {
          if (sdA in ord && sdB in ord) {   // if both "scoreDefinitionName"s are in variables
            return ord[sdA] - ord[sdB]      // use the "sequence number to sort
          } else if (sdA in ord) {          // else, if only 'a' is in 'variables' array
            return -1;                      
          } else if (sdB in ord) {          // 'a' is not but 'b' is in 'variables' array
            return 1;
          } else return (                   // both 'a' and 'b' are not in the array
            sdA < sdB ? -1 : 1              // sort using the "scoreDefinitionName"
          );
        }
      )                   // implicit return of the "sort"-ed array
    );
    
    const scores = [
        {
            "scoreDefinitionName": "_mo45",
            "score": 0,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573564",
                "globalId": null,
                "version": 0
            }
        },
        {
            "scoreDefinitionName": "_sc45",
            "score": 0,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573568",
                "globalId": null,
                "version": 0
            }
        },
        {
            "scoreDefinitionName": "_ua45",
            "score": 0,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573572",
                "globalId": null,
                "version": 0
            }
        },
        {
            "scoreDefinitionName": "KFT",
            "score": 1,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573576",
                "globalId": null,
                "version": 0
            }
        },
        {
            "scoreDefinitionName": "LFT",
            "score": 1,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573580",
                "globalId": null,
                "version": 0
            }
        },
        {
            "scoreDefinitionName": "dummy",
            "score": 1,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573584",
                "globalId": null,
                "version": 0
            }
        },
        {
            "scoreDefinitionName": "Score",
            "score": 0.32,
            "scoreDefinitionId": {
                "objectType": "ScoreDefinition",
                "idValue": "573588",
                "globalId": null,
                "version": 0
            }
        }
    ];
    
    const variables = [
      {
        variableName: "KFT",
        variable: "KFT",
        sequence: 1,
        variableDetail: {
          displayName: ""
        },
      },
      {
        variableName: "LFT",
        variable: "LFT",
        sequence: 3,
        variableDetail: {
          displayName: ""
        },
      },
      {
        variableName: "Dummy",
        variable: "dummy",
        sequence: 2,
        variableDetail: {
          displayName: ""
        }
      }
    ];
    
    // invoke the custom sort method
    // transform 'variables' array into an object
    // with key-value pair as 'variable': 'sequence'
    // This helps in sorting using the sequence
    console.log(
      'sorting scores arr using ordering from variables array...\n',
      mySort(
        scores,
        Object.fromEntries(
          variables.map(
            ({ variable, sequence }) => [variable, sequence]
          )
        )
      )
    );
    .as-console-wrapper { max-height: 100% !important; top: 0 }

    Explanation

    Inline comments added to the snippet above.