2013-02-24 2 views
1

У меня есть массив строк, которые состоят из необязательного двубуквенным строки, обозначающие весной или осенью, после чего четыре цифры года, то есть в качестве одного из следующих примеров:Javascript сортировать по по части строки

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

Я хотел бы отсортировать этот массив так, чтобы он сортировался в основном по году (т. Е. Четыре цифры, как числа), а затем (если годы равны), он сортируется так, что VT является первым, HT находится в середина и записи, которые не указывают весну или осень, являются последними.

Если я понял, функция JavaScript sort() правильно, я должен быть в состоянии осуществить sortFunction, который говорит мне, какой из двух объектов должен быть первым, а затем просто сделать вызов data.sort(sortFunction).

Я также начал работать над такой 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? 
    } 
} 

Как означают комментарии, я не имею ни малейшего понятия о том, что нужно сделать, чтобы получить сортировку по "HT", "VT" и "" правильный (за исключением, может быть, смешной серии вложенных if s ...). (Кроме того, я знаю, что приведенный выше код будет терпеть неудачу для третьего элемента в примерных данных, так как "2017.split("T") будет иметь только 1 элемент. Я разберусь с этим ...)

Является ли это хороший подход? Если да - как мне выполнить функцию, чтобы делать то, что я хочу? Если нет - что мне делать вместо этого?

ответ

1

Это может быть короче, но этот подход вычисляет сортировочный ключ первым, который затем используется для сортировки массива.

Создание ключа сортировки очень ясное и легко понять, что всегда помогает мне при создании алгоритма сортировки.

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

Я хотел бы использовать регулярное выражение с захватами и сравнить на часть

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; 
} 
0

Я разберусь с этим ...

Вы можете сделать это, получив последний элемент из массива, вместо второго:

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

Как мне выполнить функцию, чтобы сделать то, что я хочу?

Вам понадобится таблица сравнения.Похож на @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; 

Если вы не хотите таблицу, как это, вы можете использовать массив, а также:

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

я взял свобода, используя подчеркивание:

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

Вот скрипка: http://jsfiddle.net/8KHGu/ :)

Смежные вопросы