简体   繁体   English

Javascript对字符串的一部分进行排序

[英]Javascript sort on on part of string

I have an array of strings that consist of an optional two-letter string signifying spring or fall, followed by a four-digit year, ie as one of the following examples: 我有一个字符串数组,其中包含一个可选的由两个字母组成的字符串,表示春季或秋季,后跟一个四位数的年份,即以下示例之一:

var example_data = ["HT2014", "VT2013", "2017"];

I'd like to sort this array so that it is primarily sorted on the year (ie the four digits, as numbers) and then (if the years are equal) it is sorted so that VT is first, HT is in the middle and entries that do not specify spring or fall are last. 我想对该数组进行排序,以便首先对年份进行排序(即以数字表示的四个数字),然后对数组(如果年份相等)进行排序,以使VT首先位于HT,中间位于HT未指定春季或秋季的条目为最后。

If I've understood the JavaScript sort() function correctly, I should be able to implement a sortFunction that tells me which of two objects should be first, and then just make a call to data.sort(sortFunction) . 如果我正确理解了JavaScript sort()函数,那么我应该能够实现sortFunction ,该sortFunction告诉我应该首先两个对象中的哪个,然后再调用data.sort(sortFunction)

I've also started working on such a sortFunction , and come up with the following: 我也已经开始研究这样的sortFunction ,并提出了以下内容:

function specialSort(a,b) {
  var as = a.split("T");
  var bs = b.split("T");

  if (as[1] != bs[1]) {
    return as[1] - bs[1];
  } else {
    // The year is equal.
    // How do I sort on term?
  }
}

As the comments signify, I have no clue on what to do to get the sorting on "HT" , "VT" and "" correct (except maybe a ridiculous series of nested if s...). 正如评论所表明的那样,我不知道如何正确地进行"HT""VT"""的排序(除非if s ...可能是一系列荒谬的嵌套),我不知道该怎么做。 (Also, I know the above code will fail for the third item in the example data, since "2017.split("T") will only have 1 element. I'll deal with that...) (此外,我知道上面的代码对于示例数据中的第三项将失败,因为"2017.split("T")仅具有1个元素。我将处理...)

Is this a good approach? 这是一个好方法吗? If yes - how do I complete the function to do what I want? 如果是,如何完成该功能以完成我想要的? If no - what should I do instead? 如果没有,我该怎么办?

It could be shorter, but this approach calculates a sorting key first, which is then used to sort the array. 它可能会更短一些,但是这种方法首先计算一个排序键,然后将其用于对数组进行排序。

Generating the sorting key is very explicit and easy to understand, which always helps me when creating a sort algorithm. 生成排序密钥非常明确且易于理解,这在创建排序算法时总是有帮助。

// sorting key = <year> + ('A' | 'B' | 'C')
function getitemkey(item)
{
    var parts = item.match(/^(HT|VT)?(\d{4})$/);

    switch (parts[1]) {
        case 'VT': return parts[2] + 'A'; // VT goes first
        case 'HT': return parts[2] + 'B'; // HT is second
    }
    return parts[2] + 'C'; // no prefix goes last
}

function cmp(a, b)
{
    var ka = getitemkey(a),
    kb = getitemkey(b);

    // simple key comparison
    if (ka > kb) {
        return 1;
    } else if (ka < kb) {
        return -1;
    }
    return 0;
}

["HT2014", "VT2013", "2017", 'HT2013', '2013'].sort(cmp);

I'd use a regular expression with captures and compare on the parts 我会在捕获时使用正则表达式,然后在各个部分进行比较

function compare(a, b) {
    var re = /([HV]T)?(\d\d\d\d)/;
    var ma = re.exec(a);
    var mb = re.exec(b);

    // compare the years
    if (ma[2] < mb[2])
        return -1;

    if (ma[2] > mb[2])
        return 1;

    // years are equal, now compare the prefixes
    if (ma[1] == mb[1])
        return 0;

    if (ma[1] == 'VT')
        return -1;

    if (mb[1] == 'VT')
        return 1;

    if (ma[1] == 'HT')
        return -1;

    return 1;
}

I'll deal with that... 我会处理...

You can do that by getting the last item from the array, instead of the second: 您可以通过从数组中获取最后一项而不是第二项来做到这一点:

var lastCmp = as.pop() - bs.pop();
if (lastCmp) // != 0
    return lastCmp;
else
    // compare on as[0] / bs[0], though they might be undefined now

how do I complete the function to do what I want? 如何完成该功能以完成我想要的?

You will need a comparison index table. 您将需要一个比较索引表。 Similiar to @Jack's switch statement, it allows you to declare custom orderings: 与@Jack的switch语句类似,它允许您声明自定义顺序:

var orderingTable = {
    "V": 1,
    "H": 2
    // …
},
    def = 3;
var aindex = orderingTable[ as[0] ] || def, // by as[0]
    bindex = orderingTable[ bs[0] ] || def; // by bs[0]
return aindex - bindex;

If you don't want a table like this, you can use an array as well: 如果您不想要这样的表,则也可以使用数组:

var ordering = ["V", "H" /*…*/];
var *index = ordering.indexOf(*key)+1 || ordering.length+1;

I took the liberty of using underscore: 我冒昧使用下划线:

var example_data = ["2002","HT2014", "VT2013", "2017", "VT2002", "HT2013"];

var split = _.groupBy(example_data, function(val){ return val.indexOf('T') === -1});

var justYears = split[true].sort();
var yearAndTerm = split[false].sort(function(a,b){
    var regex = /([HV])T(\d\d\d\d)/;
    var left = regex.exec(a);
    var right = regex.exec(b);

    return left[2].localeCompare(right[2]) || right[1].localeCompare(left[1]);

});

var sorted = yearAndTerm.concat(justYears);
console.log(sorted);

Here is the fiddle: http://jsfiddle.net/8KHGu/ :) 这是小提琴: http : //jsfiddle.net/8KHGu/ :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM