0

我有一个奇怪的数组,我需要以某种方式进行排序,我不确定如果没有大量的体力劳动它是否可行。

考虑数组:[ '1a', '2a', '2aa', '5-6', '1', '2', '3', '20' , '7', '8']

它是一个字符串数组。正确排序,它看起来像:

[ '1', '1a', '2', '2a', '2aa', '3', '5-6', '7', '8', '20' ]

把它想象成一个大纲编号系统。

我怎样才能按这个顺序排序?

这是一个 jsfiddle,显示了常规排序如何使用其默认的字典行为来处理它(它实际上非常接近它所需要的):

http://jsfiddle.net/qkE9m/

我在 node.js 工作,并且可以使用 underscore.js。

4

2 回答 2

1

好的,这是我解决这个问题的尝试。该代码现在非常冗长,但我正在研究如何缩小它,并将在我进行时更新我的​​答案。这应该足以解决问题,让您移动。我会将我的代码作为节点模块发布,因为那是你的环境。

它的要点是它将项目分解成可以单独分类的单独部分。它并行循环这些数组中的每一个,一旦发现不匹配,它将运行基本的排序比较。

排序器.js

// regex patterns to determine how to "parse" an input item
var patterns = [
    /^([a-zA-Z]+)$/,                      // only letters
    /^(\d+)$/,                          // only contains an integer
    /^(\d+)\-\d+$/,                     // contains 2 integers separated by a hyphen
    /^(\d+)([a-z]+)?\-(\d+)([a-z]+)?$/, // contains a 2 integer/letter combos separated by a hyphen
    /^(\d+)([a-z]+)$/                   // contains an integer followed by letters
];

function itemComparator(item) {
    var len = patterns.length,
        matches, x, regex;

    for (x = 0; x < len; x++) {
        regex = patterns[x];
        if (regex.test(item)) {
            matches = item.match(regex).slice(1);
            if (/^\d+$/.test(matches[0])) {
                matches[0] = parseInt(matches[0], 10);
            }
            return matches;
        }
    }

    throw new Error("could not parse item for comparison: " + item);
}

module.exports = function (a, b) {
    var compA = itemComparator(a),
        compB = itemComparator(b),
        x, len, tmpA, tmpB, typeA, typeB; // tmp vars

    // find the largest size, so we don't miss anything
    len = Math.max(compA.length, compB.length);

    // loop each comp arr in parallel
    for (x = 0; x < len; x += 1) {
        // store for speed
        tmpA = compA[x];
        tmpB = compB[x];
        typeA = typeof tmpA;
        typeB = typeof tmpB;

        // if the elements are not equal
        if (tmpA !== tmpB) {
            // then do the comparison, and stop the loop
            if (typeA === typeB) {
                return tmpA < tmpB ? -1 : 1;
            } else if (typeA === "undefined") {
                return -1;
            } else if (typeB === "undefined") {
                return 1;
            } else if (typeA === "string") {
                return -1;
            } else if (typeB === "string") {
                return 1;
            } else {
                console.warn("unexpected condition for %s (%s) and %s (%s)", tmpA, typeA, tmpB, typeB);
                return 0;
            }
        }
    }
};

测试.js

var sorter = require("./sorter"),
    arr = [
        '1a', 'aa', '2a', '2aa', '5-6', '1', '2', '3', 'DBA', 'bb',
        '20', '2b', '7', '8', '125a', '33a-35', 'ABC',
        '3aaa-4c', '3aaa-52d', 'AA', 'c', '5dd', 'aa'
    ];

console.log(arr.sort(sorter));

// [ 'AA',
//   'ABC',
//   'DBA',
//   'aa',
//   'aa',
//   'bb',
//   'c',
//   '1',
//   '1a',
//   '2',
//   '2a',
//   '2aa',
//   '2b',
//   '3',
//   '3aaa-4c',
//   '3aaa-52d',
//   '5-6',
//   '5dd',
//   '7',
//   '8',
//   '20',
//   '33a-35',
//   '125a' ]
于 2012-11-02T17:13:35.403 回答
0

我不知道您的实际数据是什么样的,但这应该会推动您朝着正确的方向前进,我认为:

[ '1a', '2a', '2aa', '5-6', '1', '2', '3', '20' , '7', '8'].sort(function(a,b)
{
    if (parseFloat(a) !== parseFloat(b))
    {
        return parseFloat(a) - parseFloat(b);
    }
    if (a.charAt(0) !== b.charAt(0))
    {//just to be on the safe side
        return +(a[0]) - +(b[0]);
    }
    return a.length - b.length;
});
//result:
["1", "1a", "2", "2a", "2aa", "3", "5-6", "7", "8", "20"]
于 2012-11-02T16:30:50.040 回答