对包含数字和字符串的数组进行排序

20

我试图对包含字符串、数字和数字格式的字符串(例如'1'、'2')的数组进行排序。我希望对该数组进行排序,以便排序后的数组首先包含数字,然后是包含数字的字符串,最后是字符串。

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

我还尝试过

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

“2”和“3”在“9”之后有什么原因吗?对于这种排序,您可以进行两次排序或进行单个唯一复杂排序。 - briosheje
因为它们是字符串。看起来 OP 想要的是首先是数字,然后是字符串。 - ksav
2
"@briosheje",由于它们是字符串,所以"2"和 "3"在9之后。因此,顺序是[整数,整数字符串,非数字字符串] - Nick Parsons
“数字字符串”应该如何排序?作为数字还是作为字符串? - Jonas Wilms
12个回答

21

最短的可能是:

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

它并没有对字符串数字进行排序,是否应该排序呢? - NikxDa
@nikxda,实际上应该这样 - Jonas Wilms
有以下数组:["a", "5", "1", "-1", 17, "abc", 23, -5, 0, "17"],排序后会将"17"排在"5"之前。 - NikxDa
@NikxDa 好的,它按字典顺序对它们进行排序,不确定是否需要这样做。 - Jonas Wilms
这个问题基本上由你和我回答了。我唯一看到的区别是祝你好运。 - Volod
显示剩余2条评论

11

您可以使用 .filter() 将数字和非数字数据类型分离,然后对数字进行排序,再将非数字放在其后。

请查看以下示例(阅读代码注释以了解说明):

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"]


2
性能很差。Jonas的解决方案用单个排序包装起来。 - Jony-Y
7
相反,性能更好。这被称为“分而治之” 。由于排序通常是O(n.log(n)),对基数n进行两次排序比对基数2n进行一次排序更好。无论如何,争论排序少量项目的性能是没有意义的。 - YSC
2
@Jony-Y 不同意。如果将 nums.includes(x) 替换为 typeof x === "string",理论上它会更快(但需要更多的内存)[在 JavaScript 中,性能总是一个不确定的事情]。 - Jonas Wilms
不确定你在这里是否正确,你需要支付O(n)、O(mlogm)、O(n*m)和O(plogp),而在另一种解决方案中,你只需要支付nlogn。 - Jony-Y
@JonasWilms 哦,是的。谢谢你指出来。我已经更新了我的答案 :) - Nick Parsons
显示剩余2条评论

4

看起来你在第二次尝试中完成了大部分工作。 我所做的只是使用Array.concatnumberchar的排序结果合并在一起。

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)


嗨,我尝试了这个代码 "result = (number.sort((a,b)=> a>b)).concat(char.sort((a,b)=> a>b))"。但是我没有得到期望的输出结果。您能告诉我这两者有什么不同吗? - Komal Bansal
3
@komal a>b 返回 truefalse,但是需要一个数字。 - Jonas Wilms

3

试试这个

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);

这里使用了 Array.prototype.sort 可选函数来对一个数组中的元素进行排序。它必须返回一个数字。如果数字 > 0,则 b 先于 a。如果数字 < 0,则 a 先于 b。如果是 0,则它们的位置保持不变。


解释已添加,附带MDN链接。 - Sergio Tx

2
我想进一步减少循环数组的次数,以降低复杂度并提高性能。您可以编写自定义排序函数,在其中根据每个字符的charCode值计算字符串值并将它们相加,然后处理数字。
在这个代码示例中,我使用5的幂来表示字符串值,以确保字符串值大于数字值。这可以根据用例和处理的数据类型进行调整。
但是,请注意,该方法的缺点在于性能受到所处理字符串长度的影响,请注意。

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"]


2

这是您需要的内容!

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)

我的策略是先找到所有的三个块(数字,数值和字符串),然后将它们连接起来。


2

尝试使用以下内容:

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);

这段代码会创建三个数组,一个用于存放数字,一个用于存放包含数字的字符串,另一个用于存放纯字符串。它将每个元素分类到相应的数组中,最后按照正确的顺序将它们全部连接起来。


1

我们可以在sort函数中使用localeCompare函数来对数组进行排序,如下:

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


无法正确排序数字,例如:const items = [3, 'rob', 'peter', 43, 0, 100, 1, -222];,排序结果为 [ -222, 0, 1, 100, 3, 43, 'peter', 'rob' ]。需要将 100 排在 1 前面。 - equiman

1
你可以使用Array.sort()方法。
你只需要提供一个函数来控制每个比较的排序标准。
例如:
// 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

显然,typeClassify() 函数的功能可以融合到 sortCriteria() 中,以节省每次比较时的函数调用。但是为了清晰起见,我更喜欢将其分开。

1
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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接