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

Posted

技术标签:

【中文标题】对包含数字和字符串的数组进行排序【英文标题】:Sort an array which contains number and strings 【发布时间】:2019-05-26 06:32:25 【问题描述】:

我正在尝试对包含字符串、数字和数字的数组进行排序(例如“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

【问题讨论】:

9 后面有“2”和“3”的理由吗?对于这种排序,您可以排序两次或进行一次唯一的复杂排序。 @briosheje 因为它们是字符串。看起来 OP 首先想要数字,然后是字符串。 @briosheje "2" 和 "3" 在 9 之后,因为它们是字符串,所以它似乎是 [ints, integer_strings, non_numeric_strings] “数字作为字符串”应该如何排序?作为 nbers 还是作为字符串? 【参考方案1】:

最短的大概是:

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

【讨论】:

它不会对字符串数字进行排序。应该吗? @nikxda 实际上应该 拥有这个数组:["a", "5", "1", "-1", 17, "abc", 23, -5, 0, "17"]"17" 排在"5" 之前。 @NikxDa 很好,它按字典顺序对它们进行排序,不确定是否需要 所以这不是“尝试”,是吗?【参考方案2】:

您可以使用.filter() 分隔两种数据类型,先对数字进行排序,然后对非数字进行排序。

请参阅下面的工作示例(阅读代码 cmets 进行解释):

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

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

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

【讨论】:

这里的性能很差。 Jonas 的解决方案用一个单一的排序结束了它。 反而性能更好。这称为divide and conquer。由于排序通常是 O(n.log(n)),因此制作 2 种基数 n 比制作一种基数 2n 更好。无论如何,争论排序几个项目的性能是没有意义的。 @Jony-Y 不同意。如果将nums.includes(x) 替换为typeof x === "string",它会明显更快(但需要更多内存)[理论上,JS 中的性能始终是不确定的] @JonasWilms 要达到同样的效果,应该是!== "number" 不确定你在这里是否正确,你必须支付 O(n) 然后 O(mlogm) 然后 O(n*m) 然后 O(plogp) 在其他解决方案中你必须支付nlogn【参考方案3】:

看来您在第二次尝试中已经完成了大部分工作。 我在这里所做的只是使用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)

【讨论】:

嗨,我试过这个“结果 = (number.sort((a,b)=> a>b)).concat(char.sort((a,b)=> a> b))”。但我没有得到预期的输出。你能告诉我这两个有什么不同吗 @komal a>b 返回 truefalse 而应该是一个数字【参考方案4】:

你来了!

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)

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

【讨论】:

【参考方案5】:

试试这个

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 先行。如果数字

【讨论】:

添加了 MDN 链接的说明。【参考方案6】:

我想更进一步,避免多次循环数组以降低复杂性,从而提高性能。

您可以执行自定义排序功能,根据每个字符 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"]

【讨论】:

【参考方案7】:

试试这个:

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

它的作用是创建三个数组,一个用于数字,一个用于包含数字的字符串,一个用于字符串。它将每个元素排序到适当的数组中,然后最终以正确的顺序将它们连接在一起。

【讨论】:

【参考方案8】:
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);

【讨论】:

【参考方案9】:

你仍然可以使用 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() 以在每次比较时保存函数调用。为了清楚起见,我宁愿把它分开。

【讨论】:

【参考方案10】:

我们可以利用sort函数内部的localeCompare函数对数组进行排序

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

【讨论】:

【参考方案11】:

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)

【讨论】:

【参考方案12】:

有点粗糙,但它应该可以适当地处理任务

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

【讨论】:

以上是关于对包含数字和字符串的数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

您可以按值对包含数字的字符串数组进行排序吗? [复制]

对包含数字字符串的文件名数组进行排序

Java:以数字方式对字符串数组进行排序

如何对R中元素包含字母和数字的字符向量进行排序?

排序包含字符串和整数的数组列表

如何按字典顺序对 ArrayList 进行排序?