对象数组的复杂排序

时间:2015-10-09 19:55:18

标签: javascript jquery arrays knockout.js

所以我一直在研究这项任务已经有一段时间了,我遇到了问题。我一遍又一遍地尝试和重写,似乎无法为此提出足够好的解决方案。

我正在尝试将一个对象数组排序到另一个对象数组中。我正在使用淘汰赛,但如果可以在vanilla JS或jQuery中更直接地完成,那么解决方案不必包含knockout。

我将解释:

我们从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

非常感谢任何贡献!

2 个答案:

答案 0 :(得分:0)

看起来你不需要排序它们就像 group 它们一样。他们似乎已经井井有条。您需要做的就是浏览列表,看看每个列表是否与前一个序列相同。如果是,那就是你正在建造的displaySerial的结尾;如果没有,你开始一个新的displaySerial。

也许棘手的部分是确定它们是否是顺序的。我选择使用正则表达式来分割尾随数字。如果非数字部分相等且数字不同,则为顺序。

此处不需要Knockout或jQuery。你没有对DOM做任何事情。您可以使用实用程序功能,但没有太多理由。我只是用Knockout来显示结果。

如果你需要对它们进行排序,你可以使用比较函数和相同的正则表达式分割器,首先比较非数字部分,如果非数字部分相等则数字。< / p>

&#13;
&#13;
// 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});
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我正在附加基于lodash的解决方案。我假设你的价值不一定要排序。请注意,我添加了更多值以正确显示其排序和分组,并且我更改了顺序。

<script src="https://cdn.rawgit.com/lodash/lodash/3.0.1/lodash.min.js"></script>
var data = require('./path/to/index')