0

I'm trying to sort an array of string that sometimes contain numbers.

Here are examples of the array potentially received and the expected result:

  • ["12W", "60W", "25W"] -> ["12W","25W","60W"]
  • ["IP67", "IP68", "IP20"] -> ["IP20","IP67","IP68"]
  • ["White", "Red", "Black"] -> ["Black", "Red", "White"]
  • ["100cm", "10cm", "50cm"] -> ["10cm","50cm","100cm"]
  • ["3000°K", "2700°K", "2000°K"] -> ["2000°K","2700°K","3000°K"]

Here's my actual code: all_values is the array i have to sort.

const customSort = (a, b) => {
   return (Number(a.match(/(\d+)/g)[0]) - Number((b.match(/(\d+)/g[0])))
;};

const hasNumber = (myString) => {
   return /\d/.test(myString);};

// Sort filters
this.product.product_filter.map(filter => {
   if (hasNumber) {
      filter.all_values = filter.all_values.sort(customSort);
   } else {
      filter.all_values = filter.all_values.sort();}
});

Thanks in advance for your help.

Stev0x
  • 52
  • 11

3 Answers3

2
var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));
Aber Abou-Rahma
  • 174
  • 1
  • 9
0

I believe your issue lies in how you are using hasNumber. If you are using it as a conditional, it will always be truthy. A function in JavaScript is always truthy, which means your first condition will always be met and will never hit your else block.

I think you are looking to see if any elements in the array can be converted to a number. In this case, you need to inspect the array in its entirety. This is what Array#some or Array#every are designed for. Depending on your requirements, you can either:

  1. Check if every element in the array can be converted to a number or
  2. Check if at least one element can be converted.

In either situation, you are inspecting a single string at any point in time. I believe hasNumber should be renamed isNumber, for clarity's sake.

const isNumber = (myString) => /\d/.test(myString);};
// ...
const hasNumber = filter.every(str => isNumber(str)) // if every element the array can be converted to a number
if (hasNumber) {
Andrew
  • 7,201
  • 5
  • 25
  • 34
  • Thank you for your explanation which, although I found a solution, allows me to understand part of my problem :) – Stev0x Nov 29 '20 at 19:18
0

You can branch inside the the callback to the Array.sort:

1-if the elements contain numeric values then sort according to those values

2-else sort according to Alphabetic order

function sortAlphaNumeric(arr) {
    return arr.sort((first,second) => {
        let re = /\d+/;
        if(re.test(first) && re.test(second)){
            return parseInt(first.match(re) - parseInt(second.match(re)))
        }
        else{
            return first.codePointAt(0) - second.codePointAt(0) 
        }
    })
}

console.log(sortAlphaNumeric(["12W", "60W", "25W"]))
console.log(sortAlphaNumeric(["IP67", "IP68", "IP20"]))
console.log(sortAlphaNumeric(["White", "Red", "Black"]))
console.log(sortAlphaNumeric(["100cm", "10cm", "50cm"]))
console.log(sortAlphaNumeric(["3000°K", "2700°K", "2000°K"]))
Alan Omar
  • 4,023
  • 1
  • 9
  • 20