Home > Blockchain >  How to sort an array of objects on the basis of properties which are provided by another array of ob
How to sort an array of objects on the basis of properties which are provided by another array of ob

Time:05-30

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 ?

CodePudding user response:

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.

CodePudding user response:

A comparison function could be implemented in a way that it compares score-items first according to a bound map of predefined precedence entries where the key was retrieved from the variable value and and the precedence value was retrieved from the sequence value of the 2nd array's items and in a second step compares score-items by their scoreDefinitionNames according to an ascending sort order.

function compareScoreItemsByDefinitionNameAndBoundPrecedence(a, b) {
  const precedenceLookup = this;

  const aName = a.scoreDefinitionName;
  const bName = b.scoreDefinitionName;
  const aPrecedence = precedenceLookup.get(aName) ?? null;
  const bPrecedence = precedenceLookup.get(bName) ?? null;

  return (
    (aPrecedence === null && bPrecedence !== null && 1) ||    
    (aPrecedence !== null && bPrecedence === null && -1) ||
    (aPrecedence !== null && bPrecedence !== null && aPrecedence - bPrecedence) ||
    // ascending name order if no predefined precedence
    // is available or precedence comparison value was zero.
    aName.localeCompare(bName)
  );
}

const namePrecedence = [{
  variableName: "KFT",
  variable: "KFT",
  sequence: 1,
  variableDetail: {
    displayName: ""
  },
}, {
  variableName: "LFT",
  variable: "LFT",
  sequence: 3,
  variableDetail: {
    displayName: ""
  },
}, {
  variableName: "Dummy",
  variable: "dummy",
  sequence: 2,
  variableDetail: {
    displayName: ""
  }
}];
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
  }
}];

console.log(
  '... key value tuple of the to be created and bound precedence map ...',
  namePrecedence
    .map(({ variable, sequence }) => [variable, sequence])
);
scores.sort(
  compareScoreItemsByDefinitionNameAndBoundPrecedence
    .bind(
      new Map(
        namePrecedence
          .map(({ variable, sequence }) => [variable, sequence])
      )
    )
);
console.log({ scores });
.as-console-wrapper { min-height: 100%!important; top: 0; }

  • Related