我正在寻找最简单的方法来排序由数字和文本组成的数组,以及这些组合。

例如,

'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'

变成

'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'

这将与我在这里问的另一个问题的解决方案结合使用。

排序函数本身工作,我需要的是一个函数,可以说'19asd'小于'123asd'。

我用JavaScript写的。

我在找一个自然排序的函数。


当前回答

基于kennebec的答案,并使用Brian Huisman和David koelle创建的代码,这里是一个对象数组排序的修改原型:

//Usage: unsortedArrayOfObjects.alphaNumObjectSort("name");
//Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}];
//Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}]

// **Sorts in place**
Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) {
  for (var z = 0, t; t = this[z]; z++) {
    this[z].sortArray = new Array();
    var x = 0, y = -1, n = 0, i, j;

    while (i = (j = t[attribute].charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        this[z].sortArray[++y] = "";
        n = m;
      }
      this[z].sortArray[y] += j;
    }
  }

  this.sort(function(a, b) {
    for (var x = 0, aa, bb; (aa = a.sortArray[x]) && (bb = b.sortArray[x]); x++) {
      if (caseInsensitive) {
        aa = aa.toLowerCase();
        bb = bb.toLowerCase();
      }
      if (aa !== bb) {
        var c = Number(aa), d = Number(bb);
        if (c == aa && d == bb) {
          return c - d;
        } else {
          return (aa > bb) ? 1 : -1;
        }
      }
    }

    return a.sortArray.length - b.sortArray.length;
  });

  for (var z = 0; z < this.length; z++) {
    // Here we're deleting the unused "sortArray" instead of joining the string parts
    delete this[z]["sortArray"];
  }
}

其他回答

想象一个数字0填充函数n => n. padstart(8, "0"),它接受任何数字并填充它,即。

"19" -> "00000019" "123" -> "00000123"

此函数可用于帮助对“19”字符串进行排序,使其出现在“123”字符串之前。

让我们添加一个regex /\d+/g创建自然展开函数str => str.replace(/\d+/g, n => n. padstart(8, "0")),它只找到字符串中的数字部分并填充它们,即。

“19亿。”->“00000019asd” “123asd”->“00000123asd”

现在,我们可以使用这个自然展开函数来帮助实现自然排序:

预约名单= [ “123asd”, “19asd”, “12345asd”, “asd123”, “asd12” ]; 几点ne str = = > str。replace (\ d + / g, n = > n . padStart(8),“0”; 征服nc = (a,b) => ne(a).localeCompare(ne,b); 控制台日志(名单。文件夹(ne)。(排序);-内部评估 控制台日志(名单。(nc)排序;/ /论点

由list.map(ne).sort()演示的中间结果显示了ne自然展开函数的功能。它只对字符串的数字部分实现数字0填充,而字母表组件保持不变。

[
  "00000019asd",
  "00000123asd",
  "00012345asd",
  "asd00000012",
  "asd00000123"
]

解决方案的最终版本实现了一个自然顺序比较器nc,实现为(a,b) => ne(a).localeCompare(ne(b)),并在list.sort(nc)中使用它,以便正确排序:

[
  "19asd",
  "123asd",
  "12345asd",
  "asd12",
  "asd123"
]

截至2019年,功能最齐全的处理此问题的库似乎是自然顺序库。

import { orderBy } from 'natural-orderby'

const unordered = [
  '123asd',
  '19asd',
  '12345asd',
  'asd123',
  'asd12'
]

const ordered = orderBy(unordered)

// [ '19asd',
//   '123asd',
//   '12345asd',
//   'asd12',
//   'asd123' ]

它不仅接受字符串数组,还可以根据对象数组中某个键的值进行排序。它还可以自动识别和排序字符串:货币、日期、货币和其他一堆东西。

令人惊讶的是,当gzip时,它也只有1.6 kB。

基于kennebec的答案,并使用Brian Huisman和David koelle创建的代码,这里是一个对象数组排序的修改原型:

//Usage: unsortedArrayOfObjects.alphaNumObjectSort("name");
//Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}];
//Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}]

// **Sorts in place**
Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) {
  for (var z = 0, t; t = this[z]; z++) {
    this[z].sortArray = new Array();
    var x = 0, y = -1, n = 0, i, j;

    while (i = (j = t[attribute].charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        this[z].sortArray[++y] = "";
        n = m;
      }
      this[z].sortArray[y] += j;
    }
  }

  this.sort(function(a, b) {
    for (var x = 0, aa, bb; (aa = a.sortArray[x]) && (bb = b.sortArray[x]); x++) {
      if (caseInsensitive) {
        aa = aa.toLowerCase();
        bb = bb.toLowerCase();
      }
      if (aa !== bb) {
        var c = Number(aa), d = Number(bb);
        if (c == aa && d == bb) {
          return c - d;
        } else {
          return (aa > bb) ? 1 : -1;
        }
      }
    }

    return a.sortArray.length - b.sortArray.length;
  });

  for (var z = 0; z < this.length; z++) {
    // Here we're deleting the unused "sortArray" instead of joining the string parts
    delete this[z]["sortArray"];
  }
}

在使用localeCompare的现代浏览器中,这是可能的。通过传递numeric: true选项,它将智能地识别数字。你可以使用sensitivity: 'base'实现不区分大小写。它在Chrome, Firefox和Internet Explorer 11上进行了测试。

举个例子。它返回1,这意味着2后面是10:

'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})

为了提高对大量字符串进行排序时的性能,本文说:

当比较大量字符串时,例如对大型数组排序时,最好创建Intl。对象,并使用其compare属性提供的函数。

var collator = new Intl。排序器(未定义,{numeric: true,灵敏度:'base'}); var myArray = ['1_Document', '11_Document', '2_Document']; console.log (myArray.sort (collator.compare));

如果你有一个对象数组,你可以这样做:

myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});

var myArrayObjects = [{ “id”: 1、 "name": "1例" }, { “id”:2 "name": "100个例子" }, { “id”:3, "name": "12例" }, { “id”:4 "name": "5例" }, ] myArrayObjects = myArrayObjects。排序(函数(a, b) { 返回a.name.localeCompare(b.name, undefined, { 数字:没错, 灵敏度:‘基地’ }); }); console.log (myArrayObjects);