【问题标题】:Javascript sort algorithm for linked sections objects array链接部分对象数组的Javascript排序算法
【发布时间】:2018-04-27 07:40:27
【问题描述】:

我有以下需要以特殊方式排序的对象数组:

var sections = [
    {begin:"test3", end:"test4"},
    {begin:"test5", end:"test2"},
    {begin:"test2", end:"test3"},
];

所有部分都通过sectionA.end == sectionB.begin 链接在一起,因此排序操作的结果应该是:

var sectionsSorted = [
    {begin:"test5", end:"test2"},
    {begin:"test2", end:"test3"},
    {begin:"test3", end:"test4"}
];

我想在Array.prototype.sort() 方法中执行此操作。我意识到如果begin 在任何部分都不是end,那么可以找到开始部分,但从那里开始我很多。有人知道如何实现这样的东西吗?

我做了一个 JSFiddle:https://jsfiddle.net/fxmnxh8L/1/

【问题讨论】:

  • 什么定义了新订单的起点?最大的begin?还是只有一个订单满足条件,您必须搜索正确的组合?数据是否保证包含可链接值的完整链?
  • 起点由section.begin not in [all sections.end]定义。希望我描述得当

标签: javascript arrays algorithm sorting


【解决方案1】:

试试这个:

var sections = [
    {begin:"test3", end:"test4"},
    {begin:"test5", end:"test2"},
    {begin:"test2", end:"test3"},
];

sections.sort((s1, s2) => {
  return s1.end === s2.begin ? -1 : 1;
});

console.log(sections);

编辑:上述解决方案不起作用(请参阅 cmets 了解原因)。看看以下使用递归方法比较两个给定部分的解决方案:

var sections = [    
    {begin: "test4", end: "test7"},
    {begin: "test5", end: "test2"},
    {begin: "test7", end: "test8"},
    {begin: "test2", end: "test3"},
    {begin: "test3", end: "test4"},
    {begin: "test8", end: "test9"}
];

var sectionsMap = sections.reduce((m, o) => {
    m[o.begin] = o;
    return m;
}, {});

function compare(a, b) {
    if (!sectionsMap[a.end]) {
        return 1;
    } else if (sectionsMap[a.end].begin === b.begin) {
        return -1;
    } else {
        return compare(sectionsMap[a.end], b);
    }
}

sections.sort(compare);

console.log(sections);

【讨论】:

  • 看起来很棒,唯一的问题是test5 应该在顶部。这是第一节
  • test5 在顶部
  • 当我使用 Stackoverflow 中的 Run code snippet 时,我得到了不同的结果。我也在 JSFiddle 中尝试过。也许它没有正确确定整体开始?
  • 尝试将回调返回改为:return s1.end === s2.begin ? -1:s2.end === s1.begin? 1 : 0;
  • 您可以尝试使用 3 个以上的对象。那么这种方法的问题是,您没有两个未连接对象的相对顺序。对于像数字或字符串这样的值,给出了定义的顺序,你实际上不知道某些标记的顺序。
【解决方案2】:

你不能用Array#sort对数组进行排序,因为你需要对定义的前辈、项目和后继者进行稳定的排序,只有在你查看两个元素时才给出。

因此,您需要一种不同的方法,将所有部分链接起来,然后从这些部分中获取结果。

var sections = [{ begin: "test3", end: "test4" }, { begin: "test5", end: "test2" }, { begin: "test2", end: "test3" }],
    nodes = Object.create(null),
    begin = Object.create(null),
    end = Object.create(null),
    result;

sections.forEach(function (o) {
    nodes[o.begin] = o;
    begin[o.begin] = { a: [o.begin, o.end] };
    end[o.end] = begin[o.begin];

    if (begin[o.end]) {
        begin[o.end].a.unshift(o.begin);
        begin[o.begin] = begin[o.end];
        delete begin[o.end];
        delete end[o.end];
    }

    if (end[o.begin]) {
        Array.prototype.splice.apply(begin[o.begin].a, [0, 1].concat(end[o.begin].a));
        end[o.begin].a = begin[o.begin].a;
        delete begin[o.begin];
        delete end[o.end];
    }
    delete end[o.begin];
});

result = Object.keys(begin).map(function (k) {
    return begin[k].a.slice(0, -1).map(function (n) {
        return nodes[n];
    });
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 有点意思。我也想过这样的解决方案,但认为如果没有额外数据结构的解决方案会很好。如果我找不到任何其他解决方案,我会接受你的!谢谢!
【解决方案3】:

试试:

function compare(a,b) {
 if (a.end < b.end)
    return -1;
 if (a.end > b.end)
    return 1;
      }

sections.sort(compare);

https://jsfiddle.net/Micio/Lu3wqt0v/1/

【讨论】:

  • 问题是排序不依赖于beginend的值(我的意思是比较。所以a.end &lt; b.end比较值而不是链接。简单的例子:jsfiddle.net/Lu3wqt0v/2我换了test2 test3
猜你喜欢
  • 1970-01-01
  • 2011-07-04
  • 2017-05-11
  • 1970-01-01
  • 2012-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
相关资源
最近更新 更多