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 scoreDefinitionName
s 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; }