Komal Bansal
Komal Bansal

Reputation: 809

Sort an array which contains number and strings

I am trying to sort an array which contains strings, numbers, and numbers as strings (ex. '1','2'). I want to sort this array so that the sorted array contains numbers first and then strings that contain a number and then finally strings.

var arr = [9,5,'2','ab','3',-1 ] // to be sorted
arr.sort()
// arr = [-1, 5, 9, "2", "3","ab"] // expected result
//arr = [-1, "2", 5, 9, "ab"] // actual result

I have also tried

var number =[];
var char =[];
arr.forEach(a=>{
 if(typeof a == 'number') number.push(a);
 else char.push(a);
})
arr = (number.sort((a,b)=> a>b)).concat(char.sort((a,b)=> a>b))
// arr = [-1, 5, 9, "2", "3","ab"] // expected result
//  arr = [-1, 5, 9, "2", "ab", "3"]// actual result

Upvotes: 21

Views: 14833

Answers (12)

Nick Parsons
Nick Parsons

Reputation: 50759

You can sort the numbers first and then the non-numbers by using .filter() to separate both data-types.

See working example below (read code comments for explanation):

const arr = [9, 5, '2', 'ab', '3', -1];

const nums = arr.filter(n => typeof n == "number").sort((a, b) => a - b); // If the data type of a given element is a number store it in this array (and then sort numerically)
const non_nums = arr.filter(x => typeof x != "number").sort(); // Store everything that is not a number in an array (and then sort lexicographically)

const res = [...nums, ...non_nums]; // combine the two arrays
console.log(res); // [-1, 5, 9, "2", "3", "ab"]

Upvotes: 11

igmrrf
igmrrf

Reputation: 559

A little bit crude, but it should handle the task appropriately

var mixedArray = ["a", "5", "1", "-1", 17, "abc", 23, -5, 0, "17"];

const mixedSort = (arra) => {
  arra.sort();
  return arra.sort((a, b) => {
    if (typeof a === "string" && typeof b === "string") {
      if (Number(a) < Number(b)) return -1;
      return 1;
    }
    if (typeof a === "string") {
      return 1;
    }
    if (typeof b === "string") {
      return -1;
    }
  });
};
console.log(mixedSort(mixedArray));

Upvotes: 0

Niran Manandhar
Niran Manandhar

Reputation: 1107

var myArray = [9, 5, '2', 'ab', '3', -1]
myArray.sort((a, b) => {
  let aTest = /^\d+$/.test(a);
  let bTest = /^\d+$/.test(b);
  if (aTest && bTest) {
    return parseInt(a) - parseInt(b);
  } else if (aTest) {
    return -1;
  } else if (bTest) {
    return 1;
  } else {
    return a > b ? 1 : -1;
  }
})

console.log(myArray)

Upvotes: 0

Saksham
Saksham

Reputation: 9380

We can utilize the localeCompare function inside the sort function to sort the array as

var items = [3, 'rob', 'peter', 43, 0, -222];
console.log(items.sort((a, b) => {
  return a.toString().localeCompare(b.toString());
}));

Upvotes: 1

Jack Bashford
Jack Bashford

Reputation: 44107

Try using this:

var arr = [9, 5, '2', 'ab', '3', -1];
var number = [];
var strInt = [];
var char = [];
arr.forEach(a => {
  if (typeof a === "number") {
    number.push(a);
  } else if (typeof a === "string" && /\d/.test(a)) {
    strInt.push(a);
  } else {
    char.push(a);
  }
});
arr = number.concat(strInt.concat(char));
console.log(arr);

What this does is makes three arrays, one for numbers, one for strings containing numbers, and one for strings. It sorts each element into the appropriate array, then finally concatenates them all together in the correct order.

Upvotes: 2

Jimi Pajala
Jimi Pajala

Reputation: 2368

I wanted to take this a little bit further and avoid looping array multiple times for decreased complexity and therefore increased performance.

You could do a custom sort function where you calculate string values based on each character charCode value and sum them up and other hand handle numbers as they are.

In this code example I then made string values in power of 5, that we can assure string values are larger than numeric values. This could be tweaked based on use case and which kind of data are you handling.

Downside of this approach is that performance is impacted based on how long strings are you handling so be aware of that as well.

var arr = [90000, 5, '2', 'ab', 'aa', '3', -1] // to be sorted
arr.sort((a,b) => {
  if(typeof a === 'string') {
    let temp = 0
    for (let s of a) temp += s.charCodeAt(0)
    a = Math.pow(temp, 5)
  }
  if(typeof b === 'string') {
    let temp = 0
    for(let s of b) temp += s.charCodeAt(0)
    b = Math.pow(temp, 5)
  }
  return a - b
})

console.log(arr) // [-1, 5, 90000, "2", "3", "aa", "ab"]

Upvotes: 2

Jonas Wilms
Jonas Wilms

Reputation: 138267

The shortest is probably:

 arr.sort((a, b) => ((typeof b === "number") - (typeof a === "number")) || (a > b ? 1 : -1));

Upvotes: 21

bitifet
bitifet

Reputation: 3669

You can use Array .sort() method anyway.

You just need to provide a function to control sorting criteria for every comparsion.

Example:

// First of all discretize all kinds of data you want to deal with
function typeClassify(v) {
    return typeof v == "number"
        ? "N"
        : isNaN(v) ? "s" : "n"
        // (Treat all non numeric values as strings)
    ;
};


// Second: implement the sorting function
function sortCriteria(a, b) {
    var mode = typeClassify(a) + typeClassify(b);
    switch (mode) {
        case "NN":
            return a - b;
        case "nn":
            return Number(a) - Number(b);
        case "ss":
            return a == b
                ? 0
                : a > b
                    ? -1 : 1
            ;
        case "Nn":
        case "Ns":
        case "ns":
            return -1;
        case "nN":
        case "sN":
        case "sn":
            return 1;
        default:
            throw "This must never happen";
    };
};

// And finally provide that function as a callback for .sort() method
var arr = [9,5,'2','ab','3',-1 ] // to be sorted
console.log(arr.sort(sortCriteria));

// arr = [-1, 5, 9, "2", "3","ab"] // expected result
// arr = [ -1, 5, 9, '2', '3', 'ab' ] // obtained result

Obviously the functionality of typeClassify() function can be flattened into sortCriteria() to save a function call on every comparsion. I preferred to put it apart for the sake of clarity.

Upvotes: 1

Pallamolla Sai
Pallamolla Sai

Reputation: 2493

var arr=[9,5,'2','ab','3',-1];
    var string_arr=[];
    var number_arr=[];
    var string_number_arr=[];
    for(var i=0;i<arr.length;i++)
    {

        if(typeof(arr[i])=='number')
        {
            number_arr.push(arr[i]);

        }
        else if((Number(arr[i]).toString())=="NaN")
        {
            string_number_arr.push(arr[i]);

        }
        else
        {
            string_arr.push(arr[i]);
        }

    }
    string_arr.sort();
    number_arr.sort();
    string_number_arr.sort();
    var arr=number_arr.concat(string_arr,string_number_arr);
    console.log(arr);

Upvotes: 1

Sergio Tx
Sergio Tx

Reputation: 3868

Try this

const arr = [9, 5, '2', 'ab', '3', 'AB', -1];
const sortedArr = arr.sort((a, b) => {
    if (typeof a === 'number' && typeof b === 'number') {
        return a - b;
    } else if (typeof a === 'number') {
        return -1;
    } else if (typeof b === 'number') {
        return 1;
    } else {
        return a > b ? 1 : -1;
    }
});

console.log(sortedArr);

This uses the Array.prototype.sort optional function to sort elements in one array. It must return a number. If the number > 0, b goes first. If the number < 0, a goes first. If it's 0, their position remains unchanged.

Upvotes: 3

ksav
ksav

Reputation: 20831

It seems you have done most of the work in your second attempt. All I have done here is used Array.concat to join the sorted results of number and char together.

var arr = [9, 5, '2', 'ab', '3', -1] // to be sorted
var number = [];
var char = [];
arr.forEach(a => {
  if (typeof a == 'number') number.push(a);
  else char.push(a);
})


var sorted = number.sort().concat(char.sort());
console.log(sorted)

Upvotes: 4

Nurbol Alpysbayev
Nurbol Alpysbayev

Reputation: 21891

Here you are!

const arr = [9,5,'2','ab','3',-1 ]

const numbers = arr.filter(i => typeof i === 'number');
const numerics = arr.filter(i => typeof i === 'string' && !isNaN(i));
const strings = arr.filter(i => typeof i === 'string' && isNaN(i));

numbers.sort();
numerics.sort();
strings.sort()

const result = [].concat(numbers, numerics, strings)

console.log(result)

My strategy was to first find all the three chunks (numbers, numerics and strings), then just concatting them.

Upvotes: 2

Related Questions