Using native ES2015 only (i.e. no libraries) I need to sort a list of objects by a defined set of values (think T-shirt size) AND prioritize the ones that match one of the defined values.
Sample data:
const shirt_stock= [
{size: "M"},
{size: "L"},
{size: "M"},
{size: "XM"},
{size: "XL"} ]
Defined sort order:
const sort_order = ["S", "M", "L", "XL"]
Sort code (no comments needed on use of indexOf() in sort, it's pseudo code):
shirt_stock.sort((a, b) => {
return sort_order.indexOf(b.size) - sort_order.indexOf(a.size)
})
Yields result:
> 0: "XM"
> 1: "M"
> 2: "M"
> 3: "L"
> 4: "XL"
The problem is that first result, "XM" - I want that to be at the end. In other words, I want to sort shirts that have a known size first, in the order defined in sort_order, then everything else after - bonus if the "unknown size shirts" are also sorted so they're grouped by size.
Desired result:
> 0: "M"
> 1: "M"
> 2: "L"
> 3: "XL"
> 4: "XM"
I'm stumped, what's a clean (e.g. not splitting shirt_stock into two arrays, sorting and combing back) and reasonably efficient way to achieve this?
indexOf return -1 for elements that are not found, which are then put first. You will need to use a value that's higher than all the other indices for those elements. Here's a quick way to achieve that:
shirt_stock.sort((a, b) => {
return (sort_order.indexOf(a.size)+1 || sort_order.length+1) - (sort_order.indexOf(b.size)+1 || sort_order.length+1)
})
Since you already plan on not using indexOf directly in the callback, you'll probably find a more elegant way to incorporate these default values as well :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With