最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Sorting an array of strings and numbers while maintaining the array's original order - Stack Overflow

programmeradmin0浏览0评论

I just took a coding interview (ugh.) and I could not for the life of me figure this out.

Question:

Double Sort
Please write a javascript method which accepts an array of strings. Each element can either be a number ("165") or a word ("dog"). Your method should sort and return the array such that (1) The words are in alphabetical order and the numbers in numerical order, and (2) the order of words and numbers within the array is the same.

Examples (input => output):

sort(['5', '4', 'dog', '1', 'cat'])

=> ['1', '4', 'cat', '5', 'dog']

sort(['dog', 'cat'])

=> ['cat', 'dog']

sort('5', '3')

=> ['3', '5']

I was able to write a basic sort function that sorted the array alphabetically and numerically, but I was unable to maintain the array's original order. This was what I managed to e up with in the time limit:

var multiSortArray = [5, 4, 'dog', 1, 'cat'];

var multiSort = function(arr) {
    var sortedArray = arr.sort();
    console.log(sortedArray);
}
multiSort(multiSortArray); 
which outputs: [1, 4, 5, "cat", "dog"]  

Any help'd be appreciated, I'm irritated as hell I couldn't figure this out. All I could find in SO was ordering objects which I'm not sure is what I need to do (or maybe I do. I have no idea.)

Thanks everyone!

I just took a coding interview (ugh.) and I could not for the life of me figure this out.

Question:

Double Sort
Please write a javascript method which accepts an array of strings. Each element can either be a number ("165") or a word ("dog"). Your method should sort and return the array such that (1) The words are in alphabetical order and the numbers in numerical order, and (2) the order of words and numbers within the array is the same.

Examples (input => output):

sort(['5', '4', 'dog', '1', 'cat'])

=> ['1', '4', 'cat', '5', 'dog']

sort(['dog', 'cat'])

=> ['cat', 'dog']

sort('5', '3')

=> ['3', '5']

I was able to write a basic sort function that sorted the array alphabetically and numerically, but I was unable to maintain the array's original order. This was what I managed to e up with in the time limit:

var multiSortArray = [5, 4, 'dog', 1, 'cat'];

var multiSort = function(arr) {
    var sortedArray = arr.sort();
    console.log(sortedArray);
}
multiSort(multiSortArray); 
which outputs: [1, 4, 5, "cat", "dog"]  

Any help'd be appreciated, I'm irritated as hell I couldn't figure this out. All I could find in SO was ordering objects which I'm not sure is what I need to do (or maybe I do. I have no idea.)

Thanks everyone!

Share Improve this question asked May 15, 2017 at 15:15 12Noone12Noone 831 silver badge9 bronze badges 9
  • 1 I believe that it should sort the strings and numbers but keep them in their original places. so [3, 5, 'cat', 2, 'ant'] --> [2, 3, 'ant', 4, 'cat']. so indexes that are numbers remain indexes, same with strings, but otherwise they're sorted alphabetically/numerically. – 12Noone Commented May 15, 2017 at 15:20
  • 2 @T.J.Crowder I believe that the array should be sorted, however an array position that was originally a string should remain a string, and an array position that originally held an integer should remain an integer. – Tyler Roper Commented May 15, 2017 at 15:21
  • 1 I think the correct output would be - [1, 4, 'cat', 5, 'dog'] – zenwraight Commented May 15, 2017 at 15:21
  • 1 @zenwraight OP said that in his question, it's his first example. He's saying that his own output is wrong. – Tyler Roper Commented May 15, 2017 at 15:22
  • 1 And they really gave you the numbers as strings? – T.J. Crowder Commented May 15, 2017 at 15:32
 |  Show 4 more ments

6 Answers 6

Reset to default 7

Just split the numbers and words into seperate arrays, sort them, and add back together again

function sort(arr) {
  let n = arr.filter(x =>  isNaN(x)).sort((a,b) => a.localeCompare(b));
  let c = arr.filter(y => !isNaN(y)).sort((a,b) => a-b);

  return arr.map(z => (isNaN(z) ? n : c).shift());
}

console.log(sort(['5', '4', 'dog', '1', 'cat']));

One way to do it:

var arr = ['5', '4', 'dog', '1', 'cat'];

// STEP 1: split the original array into two arrays, one for strings and one for numbers
var str = [], num = [];
arr.forEach(e => isNaN(e)? str.push(e): num.push(e));

// STEP 2: sort the two arrays
str.sort();
num.sort((a, b) => a - b); // because the numbers are actually strings we need to do a - b to implicitly convert them into numbers and sort them using the substraction result

// STEP 3: for each element in the original array, if the original item was a string then replace it with the first item in the string array (and remove the added item), if the original item was a number, do the same with the num array
arr.forEach((e, i) => arr[i] = isNaN(e)? str.shift(): num.shift());

console.log(arr);

The first thing that would have e to my mind would have been to make a map of which type of thing was in which index, then separate and sort, then zip them together again according to the type:

function sort(a) {
    const type = a.map(e => /^\d+$/.test(e));
    const nums = a.filter((e, i) => type[i]).sort((left, right) => left - right);
    const strs = a.filter((e, i) => !type[i]).sort((left, right) => left.localeCompare(right));
    let nindex = 0, sindex = 0;
    return type.map(t => t ? nums[nindex++] : strs[sindex++]);
}

console.log(sort(['5', '4', 'dog', '1', 'cat']));
// => ['1', '4', 'cat', '5', 'dog']

console.log(sort(['dog', 'cat']));
// => ['cat', 'dog']

console.log(sort(['5', '3']));
// => ['3', '5']

console.log(sort(['5', 'gazelle', '300']));
// => ['5', 'gazelle', '300']

function sort(a) {
    const type = a.map(e => /^\d+$/.test(e));
    const nums = a.filter((e, i) => type[i]).sort((left, right) => left - right);
    const strs = a.filter((e, i) => !type[i]).sort((left, right) => left.localeCompare(right));
    let nindex = 0, sindex = 0;
    return type.map(t => t ? nums[nindex++] : strs[sindex++]);
}
.as-console-wrapper {
  max-height: 100% !important;
}

Or with ES5 and earlier syntax:

console.log(sort(['5', '4', 'dog', '1', 'cat']));
// => ['1', '4', 'cat', '5', 'dog']

console.log(sort(['dog', 'cat']));
// => ['cat', 'dog']

console.log(sort(['5', '3']));
// => ['3', '5']

console.log(sort(['5', 'gazelle', '300']));
// => ['5', 'gazelle', '300']

function sort(a) {
    var type = a.map(function(e) { return /^\d+$/.test(e); });
    var nums = a.filter(function(e, i) { return type[i]; }).sort(function(left, right) {
        return left - right;
    });
    var strs = a.filter(function(e, i) { return !type[i]; }).sort(function(left, right) {
        return left.localeCompare(right);
    });
    var nindex = 0, sindex = 0;
    return type.map(function(t) {
        return t ? nums[nindex++] : strs[sindex++];
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

...but I'd've asked them a bunch of questions about the data, as I might go another way if there were hundreds of thousands of entries.

Also note ensuring a numeric parison for the numbers, and a correct lexicographic parison for the strings (within the browser's feature set, anyway).


Side note: In my version, I detected numbers like this: /^\d+$/.test(e). That only allows for integers, and doesn't allow for scientific notation. The alternative would be a variation on what adeneo did: e !== "" && !isNaN(e), which coerces e to a number if it's not blank and checks if the result was NaN (which would mean it couldn't be converted). The check for "" is because sadly, coercing "" to number gives you 0 and so just isNaN(e) would give an incorrect result for "".

This is a bit quick and not super efficient, but it's one potential solution that produces your output:

var sorter = function(array){
  let chars = [];
  let nums = [];

  array.forEach( (v,i) => {
    if(isNaN(+v)){
        chars.push(i);
    }
    else{
        nums.push(i);
    }
  });

  let newArray = [];

  let sortedChars = array.filter(a => isNaN(+a)).sort();
  let sortedNums = array.filter(a => !isNaN(+a)).sort();

  chars.forEach((value, index) => {
    newArray[value] = sortedChars[index];
  });

   nums.forEach((value, index) => {
    newArray[value] = sortedNums[index];
  });

  return newArray;
}

This could be easily done in many ways so you get your sorted array as

[1,4,5,'cat','dog']

So before sorting take another array of same size and make a mark

0 - means integer
1 - means string 

So this new array would look like this

temp = [0, 0, 1, 0, 1];

Now after you have sorted just iterate over this and replace the 0 with ining integers in order and 1 with strings

And you will get the required output.

You could use an object for the typed values and sort accordingly. Then use the original array again and map the values ot the same type for the result set.

function sort(array) {
    var order = {
            number: function (a, b) { return a - b; },
            string: function (a, b) { return a.localeCompare(b); },
            default: function () { return 0; },
        };
        temp = {};

    array.forEach(function (a) { (temp[typeof a] = temp[typeof a] || []).push(a); });
    Object.keys(temp).forEach(function (t) { temp[t].sort(order[t] || order.default); });
    return array.map(function (a) { return temp[typeof a].shift(); });
};

console.log(sort([5, 4, 'dog', 1, 'cat']));
.as-console-wrapper { max-height: 100% !important; top: 0; }

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论