I am sorting an array using the sort()
method. When there is a duplicate value I'd like to run secondary logic to decide the sort order.
For example, in the below array, I'd like to choose how red
and orange
get sorted.
This is my sorting function:
inventoryTally.sort(function (a, b) {
if (a.inventoryTotal < b.inventoryTotal) {
return 1;
}
if (a.inventoryTotal > b.inventoryTotal) {
return -1;
}
if (a.inventoryTotal === b.inventoryTotal) {
//When inventory levels are the same, call secondary logic that further compares a and b based on sales volume of those 2 product variants
//I want the variant with higher sales volume to be ordered first
//My thinking is to dynamically return 1 or -1 so that the higher sales volume variant is ordered first
//return 1;
}
});
When a.inventoryTotal === b.inventoryTotal
, I'm testing between returning 1 and -1 in order to influence sort order. However, this does not change the order in which red
and orange
are sorted and has no influence on the array.
[
{
option: 'Blue',
inventoryTotal: 12312312,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Green',
inventoryTotal: 1265,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Red',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Orange',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
}
]
I've stripped everything away to the basic function above and I think my issue is a fundamental misunderstanding of the sort()
method.
Reading the docs, returning 1
or -1
should reorder the array. However, it seems to ignore this return when the values are equal.
Where am I going wrong?
EDIT: Desired Outcome
When compared values are the same, I want to perform side calculations that ultimately return either -1 or 1. Depending on if 1 or -1 is returned, compared value order will be changed.
Return 1:
if (a.inventoryTotal === b.inventoryTotal) {
return 1;
}
[
{
option: 'Blue',
inventoryTotal: 12312312,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Green',
inventoryTotal: 1265,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Red',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Orange',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
}
]
Return -1:
if (a.inventoryTotal === b.inventoryTotal) {
return -1;
}
[
{
option: 'Blue',
inventoryTotal: 12312312,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Green',
inventoryTotal: 1265,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Orange',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
}
{
option: 'Red',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
},
]
EDIT 2: Further clarification around the initial function when a.inventoryTotal === b.inventoryTotal
CodePudding user response:
If the inventoryTotal
values are equal, then you should return a sort result based on doing a string comparison (using localeCompare
) of the two option
values. If you want to sort alphabetically ('Orange' before 'Red'), use
a.option.localeCompare(b.option)
otherwise, use
b.option.localeCompare(a.option)
localeCompare
will return either -1, 1, or 0 dependent on whether the reference string (a.option
in the first example above) occurs before, after or is equal to the comparison string.
const Variant = 'Variant'
const inventoryTally = [
{
option: 'Red',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Blue',
inventoryTotal: 12312312,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Orange',
inventoryTotal: 3,
variant: [ [Variant], [Variant], [Variant] ]
},
{
option: 'Green',
inventoryTotal: 1265,
variant: [ [Variant], [Variant], [Variant] ]
}
]
inventoryTally.sort((a, b) => {
if (a.inventoryTotal != b.inventoryTotal)
// sort descending
return b.inventoryTotal - a.inventoryTotal;
else
// sort ascending
return a.option.localeCompare(b.option);
})
console.log(inventoryTally)
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
Your thinking is correct, perhaps a more extensive example is needed?
Here's a working snippet:
let inventoryTally = [{
option: 'Blue',
inventoryTotal: 1265,
other: 5
},
{
option: 'Green',
inventoryTotal: 1265,
other: 50
},
{
option: 'Red',
inventoryTotal: 3,
other: 5
},
{
option: 'Orange',
inventoryTotal: 3,
other: 50
},
{
option: 'Blorange',
inventoryTotal: 5555,
other: 0
}
]
inventoryTally.sort(function(a, b) {
if (a.inventoryTotal < b.inventoryTotal) {
return 1;
}
if (a.inventoryTotal > b.inventoryTotal) {
return -1;
}
if (a.inventoryTotal === b.inventoryTotal) {
//When inventory levels are the same, call secondary logic that further compares a and b based on another property value
if (a.other < b.other) return 1;
if (b.other < a.other) return -1;
return 0;
}
});
console.log(inventoryTally)
CodePudding user response:
your code works correctly and arranges the objects in the array in descending order based on inventoryTotal and the equality condition also works correctly. See the output of the following code:
let myArray = [
{
option: 'Blue',
inventoryTotal: 55,
},
{
option: 'Green',
inventoryTotal: 2,
},
{
option: 'Red',
inventoryTotal: 2,
},
{
option: 'Orange',
inventoryTotal: 88,
}
];
myArray.sort(function (a, b) {
if (a.inventoryTotal < b.inventoryTotal) {
return 1;
}
if (a.inventoryTotal > b.inventoryTotal) {
return -1;
}
if (a.inventoryTotal === b.inventoryTotal) {
if(a.option.length<b.option.length){
return 1;
}else{
return -1;
}
}
});
console.log(myArray)
and compare with this:
let myArray = [
{
option: 'Blue',
inventoryTotal: 55,
},
{
option: 'Green',
inventoryTotal: 2,
},
{
option: 'Reddd',
inventoryTotal: 2,
},
{
option: 'Orange',
inventoryTotal: 88,
}
];
myArray.sort(function (a, b) {
if (a.inventoryTotal < b.inventoryTotal) {
return 1;
}
if (a.inventoryTotal > b.inventoryTotal) {
return -1;
}
if (a.inventoryTotal === b.inventoryTotal) {
if(a.option.length<b.option.length){
return 1;
}else{
return -1;
}
}
});
console.log(myArray)
CodePudding user response:
You could return something like
a.option.localeCompare(b.option) * 2 - 1;
which compares, which string starts with the "higher" letter.
(Since the functions returns 0 or 1 the * 2 - 1 is needed)