Currently I have a table displaying and it is sorting by the first column alphabetically and then by the second if there are any duplicates in the first by using two sorts as below
inventoryData = Object.values(inventoryData).sort((a, b) => {
if (a.XI_MP_POS < b.XI_MP_POS) { return -1; }
if (a.XI_MP_POS > b.XI_MP_POS) { return 1; }
return 0;
});
inventoryData = Object.values(inventoryData).sort((a, b) => {
if (a.XI_MP_DESC < b.XI_MP_DESC) { return -1; }
if (a.XI_MP_DESC > b.XI_MP_DESC) { return 1; }
return 0;
});
It's been requested that this sort be maintained but for a few select XI_MP_DESC values to appear at the top regardless of their position alphabetically, is this possible?
I would like to turn for example:
Desc | POS |
---|---|
A | A |
A | B |
A | C |
B | A |
C | A |
C | B |
C | C |
Into:
Desc | POS |
---|---|
C | A |
C | B |
C | C |
A | A |
A | B |
A | C |
B | A |
By specifying that C always appear at the top
This has been solved using
const topDescriptions = ['desc1', 'desc2'];
inventoryData = Object.values(inventoryData).sort((a, b) => {
if (a.XI_MP_POS < b.XI_MP_POS) { return -1; }
if (a.XI_MP_POS > b.XI_MP_POS) { return 1; }
return 0;
});
inventoryData = Object.values(inventoryData).sort((a, b) => {
if (a.XI_MP_DESC < b.XI_MP_DESC) { return -1; }
if (a.XI_MP_DESC > b.XI_MP_DESC) { return 1; }
return 0;
});
inventoryData = Object.values(inventoryData).sort((a, b) => {
const aIsTop = topDescriptions.includes(a.XI_MP_DESC);
const bIsTop = topDescriptions.includes(b.XI_MP_DESC);
if (aIsTop && !bIsTop) return -1;
if (bIsTop && !aIsTop) return 1;
return 0;
});
CodePudding user response:
You could take an object for the special order with a default value for unknown items:
- zero for moving to top,
- a large value for moving to bottom,
- any other value for taking a custom sorting.
Inside of the single sorting function sort
Desc
by order ascending,Desc
by string ascending.POS
by string ascending.
By using more than one function, the result is only predictable with a stable sorting algorithm.
const
data = [{ Desc: 'A', POS: 'A' }, { Desc: 'A', POS: 'B' }, { Desc: 'A', POS: 'C' }, { Desc: 'B', POS: 'A' }, { Desc: 'C', POS: 'A' }, { Desc: 'C', POS: 'B' }, { Desc: 'C', POS: 'C' }],
order = { C: 1, default: Number.MAX_VALUE };
data.sort((a, b) =>
(order[a.Desc] || order.default) - (order[b.Desc] || order.default) ||
a.Desc.localeCompare(b.Desc) ||
a.POS.localeCompare(b.POS)
);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
You can use a third sort after the first two. See the snippet below. I also corrected two mistakes in your snippet: you cannot subtract strings (you'll get a NaN) and you should sort your list in place.
const inventoryData = [
{XI_MP_POS: 1, XI_MP_DESC: 'aaa'},
{XI_MP_POS: 4, XI_MP_DESC: 'bbb'},
{XI_MP_POS: 3, XI_MP_DESC: 'ddd'},
{XI_MP_POS: 3, XI_MP_DESC: 'ccc'},
];
const topDescriptions = ['bbb', 'aaa'];
inventoryData.sort((a, b) => a.XI_MP_DESC < b.XI_MP_DESC ? -1 : a.XI_MP_DESC > b.XI_MP_DESC ? 1 : 0);
inventoryData.sort((a, b) => a.XI_MP_POS - b.XI_MP_POS);
inventoryData.sort((a, b) => {
const aIsTop = topDescriptions.includes(a.XI_MP_DESC);
const bIsTop = topDescriptions.includes(b.XI_MP_DESC);
if (aIsTop && !bIsTop) return -1;
if (bIsTop && !aIsTop) return 1;
return 0;
});
console.log(inventoryData)