2015-10-09 2 views
0

Итак, я уже давно работаю над этой задачей, и я столкнулся с проблемой. Я пробовал и переписывал снова и снова и, похоже, не мог найти достаточно хорошего решения.Комплексная сортировка для массива объектов

Я пытаюсь сортировать один массив объектов в другой массив объектов. Я использую нокаут, но решение не должно включать нокаут, если его можно сделать более непосредственно в ванильном JS или jQuery.

поясню:

Мы начнем с observableArray serials с объектами некоторые серийный номер в нем. Этот массив всегда содержит этот формат:

var serials = ko.observableArray([ 
    { number: "DFG09008", qty: 1 }, 
    { number: "DFG09009", qty: 1 }, 
    { number: "DFG09010", qty: 1 }, 
    { number: "DFG09011", qty: 1 }, 
    { number: "DFG09020", qty: 1 }, 
    { number: "ASD-0001", qty: 1 }, 
    { number: "ASD-0002", qty: 1 }, 
    { number: "HJ-DRT-06", qty: 1 }, 
    { number: "HJ-DRT-07", qty: 1 }, 
    { number: "POU055054", qty: 1 } 
]); 
// qty property is for something unrelated to this in the app 

Желаемый результат функции я пишу то, что он будет выводить на другой observableArray displaySerials, который будет использоваться, чтобы представить идею «числовой диапазон»:

var displaySerials = ko.observableArray([ 
    { beginSerial: "DFG09008", endSerial: "DFG09011" }, 
    { beginSerial: "DFG09020", endSerial: "" }, 
    { beginSerial: "ASD-0001", endSerial: "ASD-0002" }, 
    { beginSerial: "HJ-DRT-06", endSerial: "HJ-DRT-07" }, 
    { beginSerial: "POU055054", endSerial: "" } 
]); 

Таким образом, из-за serials «первых четырех членов» number собственности, "DFG09008", "DFG09009", "DFG09010", "DFG09011" иметь соответствующий префикс (DFG090) и число суффиксов, которые являются смежными (8, 9, 10, 11), они помещаются в объект, где beginSerial является самое низкое число в диапазоне (DFG09008) и endSerial является самым высоким (DFG09011). Обратите внимание, что "DFG09020" помещается в отдельный объект. Это связано с тем, что он не является последовательным с другими числами в группе, поэтому он рассматривается сам по себе.

Любой серийный номер, который не имеет никакого отношения к остальной части группы помещается в собственный объект, где endSerial свойство является пустая строка: { beginSerial: "DFG09020", endSerial: "" }

только определенные правила для пути серийные номера структурированы, что они всегда будут заканчиваться номером. Но в коллекции могут быть десятки или сотни.

только требования к допустимым решения являются вещи, упомянутые выше, а также:

  • Массив serials должен остаться без изменений по ходу этой функциональности.
  • Решение не является конкретным или зависит от какой-либо строковой структуры для сериалов, за исключением того, что они заканчиваются номером.

My jsfiddle

Любой вклад высоко ценится!

+0

Вы не включили путь вы в настоящее время сортировки в самом вопросе пока. Не могли бы вы добавить его и сообщить нам, где находится конкретная проблема? (Кроме того, вам будет полезно *** много здесь, начиная с модульных тестов. Преобразуйте свой человекообразный spec в автоматизированные тесты: это будет стоить ваше время наверняка!) – Jeroen

ответ

0

Не похоже, что вам нужно сортировать их столько, сколько группа их. Кажется, они уже в порядке. Все, что вам нужно сделать, это пройтись по списку и посмотреть, соответствует ли каждый из них предыдущему. Если это так, это конец экрана, который вы создаете; Если нет, вы начинаете новый displaySerial.

Возможно, сложная часть определяет, являются ли они последовательными. Я решил использовать регулярное выражение для разделения конечных чисел. Он последователен, если нечисловые части равны, а числа одного разные.

В этом нет необходимости в Knockout или jQuery. Вы ничего не делаете с DOM. Вы можете использовать служебные функции, но причин для этого нет. Я использовал Knockout только для отображения результатов.

Если вам нужна do, вы должны использовать функцию сравнения с тем же самым разделителем regexp, сначала сравнивая нечисловую часть, и числовое значение, если нечисловые числа были равны.

// test data 
 
var serials = [ 
 
    { number: "DFG09008", qty: 1 }, 
 
    { number: "DFG09009", qty: 1 }, 
 
    { number: "DFG09010", qty: 1 }, 
 
    { number: "DFG09011", qty: 1 }, 
 
    { number: "DFG09020", qty: 1 }, 
 
    { number: "ASD-0001", qty: 1 }, 
 
    { number: "ASD-0002", qty: 1 }, 
 
    { number: "HJ-DRT-06", qty: 1 }, 
 
    { number: "HJ-DRT-07", qty: 1 }, 
 
    { number: "POU055054", qty: 1 } 
 
]; 
 

 

 
// constructor for displaySerials array 
 
function DisplaySerial (beginSerial, endSerial) { 
 
    this.beginSerial = beginSerial; 
 
    this.endSerial = endSerial; 
 
} 
 

 
var serialPartsPattern = /(.*\D)(\d+)$/; 
 
function isSequential(s1, s2) { 
 
    if (s1 === undefined) return false; 
 
    var m1 = s1.match(serialPartsPattern), 
 
     m2 = s2.match(serialPartsPattern); 
 
    return m1[1] === m2[1] && (+m1[2] + 1) === +m2[2]; 
 
} 
 

 
var displaySerials = [], 
 
    currentSerial, 
 
    prevSerial, 
 
    currentDisplaySerial; 
 
for (var i=0; i<serials.length; ++i) { 
 
    currentSerial = serials[i].number; 
 
    if (isSequential(prevSerial, currentSerial)) { 
 
     currentDisplaySerial.endSerial = currentSerial; 
 
    } 
 
    else { 
 
     currentDisplaySerial = new DisplaySerial(currentSerial, ""); 
 
     displaySerials.push(currentDisplaySerial); 
 
    } 
 
    prevSerial = currentSerial; 
 
} 
 

 
ko.applyBindings({displaySerials: displaySerials});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<ol data-bind="foreach:displaySerials"> 
 
    <li><span data-bind="text:beginSerial"></span>...<span data-bind="text:endSerial"></span></li> 
 
    </ol>

0

Я прилагаю раствор lodash на основе. Я предположил, что ваши значения не обязательно сортируются. Обратите внимание, что я добавил больше значений, чтобы показать, что они сортируются и группируются правильно, и я изменил порядок.

var serials = [ 
 
    { number: "DFG09008", qty: 1 }, 
 
    { number: "DFG09009", qty: 1 }, 
 
    { number: "DFG09016", qty: 1 }, 
 
    { number: "DFG09010", qty: 1 }, 
 
    { number: "DFG09011", qty: 1 }, 
 
    { number: "DFG09005", qty: 1 }, 
 
    { number: "DFG09014", qty: 1 }, 
 
    { number: "DFG09015", qty: 1 }, 
 
    { number: "DFG09020", qty: 1 }, 
 
    { number: "ASD-0001", qty: 1 }, 
 
    { number: "ASD-0002", qty: 1 }, 
 
    { number: "HJ-DRT-06", qty: 1 }, 
 
    { number: "HJ-DRT-07", qty: 1 }, 
 
    { number: "POU055054", qty: 1 } 
 
]; 
 

 
var splitSerials = _.map(serials, function(serial){ 
 
    var parts = serial.number.match(/([^\d]+)(\d+)/); 
 
    return {key: parts[1], number: parts[2]}; 
 
}); 
 

 
var grouped = _.groupBy(splitSerials, 'key'); 
 

 
function chunkConsec(array){ 
 
    return _.transform(array, function(result, n){ 
 
    if(_.last(_.last(result)) === n - 1){ 
 
     _.last(result).push(n); 
 
    } else { 
 
     result.push([n]); 
 
    } 
 
    return true; 
 
    }); 
 
} 
 

 
function unchunk(array){ 
 
    if(array.length > 1){ 
 
    return [_.first(array), _.last(array)]; 
 
    } else { 
 
    return array; 
 
    } 
 
} 
 

 
var groupedArray = _.mapValues(grouped, 
 
    _.flow(
 
    _.partial(_.map, _, 'number'), 
 
    _.partial(_.map, _, _.parseInt), 
 
    _.sortBy, 
 
    chunkConsec, 
 
    _.partial(_.map, _, unchunk) 
 
)); 
 

 
function buildRange(value, key){ 
 
    var result = {beginSerial: (key + value[0])}; 
 
    result.endSerial = (value.length > 1 ? key + value[1] : ''); 
 
    return result; 
 
} 
 
function buildRanges(values, key){ 
 
    return _.map(values, function(value){ 
 
    return buildRange(value, key); 
 
    }); 
 
} 
 

 
var finalResult = _.flatten(_.values(_.mapValues(groupedArray, buildRanges))); 
 
console.log(finalResult); 
 
alert(JSON.stringify(finalResult));
<script src="https://cdn.rawgit.com/lodash/lodash/3.0.1/lodash.min.js"></script>

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