【问题标题】:What is a good algorithm and a data structure for rearrangement of items?什么是重新排列项目的好算法和数据结构?
【发布时间】:2019-10-23 11:38:57
【问题描述】:

假设我有一些项目,每个项目都有一个序列 - 较小的序列意味着项目在上面。一个项目可以对其他项目具有依赖关系/依赖关系。此外,一个项目可以有可靠的 - 即其他一些项目可能依赖于它。下面的项目列表(我在这里使用了关联的数组)列出了项目 - 每个项目的属性“dep”列出了依赖项和可依赖项。


var dependencyDict = {
  item1: {dependsOn: [], dependable: ['item3']},
  item2: {dependsOn: [], dependable: []},
  item3: {dependsOn: ['item1'], dependable: ['item4']},
  item4: {dependsOn: ['item3'], dependable: []}
}

var itemList  = {
  item1: {
    name: 'item1',
    seq: 1,
    dep: dependencyDict['item1']
  },
  item2: {
    name: 'item2',
    seq: 2,
    dep: dependencyDict['item2']
  },
  item3: {
    name: 'item3',
    seq: 3,
    dep: dependencyDict['item3']
  },
  item4: {
    name: 'item4',
    seq: 4,
    dep: dependencyDict['item4']
  }
}

根据上面的说法,项目的先后顺序是这样的:

item1
item2
item3
item4

我的目标是重新排序项目,即更改顺序(如果可能),以使依赖关系完好无损。

验证:只有在依赖关系保持不变的情况下,项目才能移动:即

  • 一个项目只能依赖于它上面的项目,即它们的序列小于项目的序列 反之亦然,即

  • 仅当项目低于项目时,项目才能将项目作为依赖项,即它们的序列大于项目的序列

例如,如果我说 move(item3, 2) - 我要求将 item3 移动到位置 2,以便新项目列表应该是这样的:

{
  item1: {
    name: 'item1',
    seq: 1,
    dep: dependencyDict['item1']
  },
  item2: {
    name: 'item2',
    seq: 3,
    dep: dependencyDict['item2']
  },
  item3: {
    name: 'item3',
    seq: 2,
    dep: dependencyDict['item3']
  },
  item4: {
    name: 'item4',
    seq: 4,
    dep: dependencyDict['item4']
}

注意序列的变化

但是如果我说 move(item3, 1),它不会,因为 item3 依赖于 item1 - 如果它移动到位置 1,item1 将转到位置 2,这使 item 只能依赖于 items 的规则无效在它上面。

我的代码处于工作状态,但我使用的 if-else 比正确的算法多

灵活性:itemlist可以放在任何数据结构中,可以使用任何算法

【问题讨论】:

  • above/below 不是适用于对象的术语。
  • 你从哪里知道,item3 依赖于item1
  • "一个项目只能依赖于它之上的项目,即它们的序列小于项目的序列,反之亦然,即项目只有在项目低于该项目时才能依赖于一个项目,即它们的序列是大于项目的序列” - 感觉这两个陈述相互矛盾,你能改写一下吗?
  • "如果我说 move(item3, 12) " - 12 是什么意思?
  • 您可能想要的是一个dependency graph 来编码您的项目之间的依赖关系。当您想要移动一个项目时,您可以通过遍历您的有序列表并标记图表中的每个项目来检查生成的订单是否有效,每次检查其所有父项是否已被标记。

标签: javascript arrays algorithm data-structures


【解决方案1】:

一些建议:

  • 如果您的数据很大且具有许多依赖项,使用Set 注册依赖项而不是数组可能更有效。
  • 消除dependsOndependable 之一,因为其中一个可以派生自另一个
  • 不要存储seq,而只依赖于数组中项目的索引。没错,这意味着您必须使用 indexOf 扫描数组,但另一方面,您不必更新移动中涉及的所有 seq 属性。
  • 使用从零开始的索引,而不是从 1 开始的位置。

这是我建议的数据结构的class 实现。

class OrderedGraph {
    constructor(pairs) {
        this._dep = new Map;
        this._order = [];
        if (pairs) for (let [item, dependsOn] of pairs) this.add(item, dependsOn);
    }
    add(item, dependsOn=[]) {
        for (let ref of dependsOn) if (!this._dep.has(ref)) throw ref + " not found";
        this._dep.set(item, new Set(dependsOn));
        this._order.push(item);
    }
    move(item, toIdx) {
        let fromIdx = typeof item === "number" ? item : this._order.indexOf(item);
        if (fromIdx < 0) throw "not found: " + item
        if (typeof item === "number") item = this._order[item];
        let dep = this._dep.get(item);
        let ok = fromIdx > toIdx
            ? !this._order.slice(toIdx, fromIdx).some(it => dep.has(it))
            : !this._order.slice(fromIdx+1, toIdx+1).some(it => this._dep.get(it).has(item));
        if (ok) this._order.splice(toIdx, 0, ...this._order.splice(fromIdx, 1));
        return ok;
    }
    indexOf(item)  { return this._order.indexOf(item) }
    includes(item) { return this._dep.has(item) }
    * values()     { yield * this._order }
    [Symbol.iterator]() { return this.values() }
}

// Example use
let data = new OrderedGraph([
    ["item1", []],
    ["item2", []],
    ["item3", ["item1"]],
    ["item4", ["item3"]]
]);

// Some actions on the data object:
console.log(JSON.stringify(Array.from(data)));
console.log("success moving 'item3' to 0? ", data.move("item3", 0));
console.log(JSON.stringify(Array.from(data)));
console.log("success moving 'item3' to 1? ", data.move("item3", 1));
console.log(JSON.stringify(Array.from(data)));
console.log("success moving 'item3' to 1? ", data.move("item3", 1));
console.log(JSON.stringify(Array.from(data)));
console.log("success moving 'item3' to 2? ", data.move("item3", 2));
console.log(JSON.stringify(Array.from(data)));
console.log("index of 'item3': ", data.indexOf("item3"));

【讨论】:

  • 谢谢。看起来很棒。
【解决方案2】:

您可以使用所需新节点列表的索引来检查依赖关系。

function move(node, position) {
    var nodes = Object.keys(itemList).sort(({ seq: a }, { seq: b }) => a - b);

    nodes.splice(position - 1, 0, ...nodes.splice(itemList[node].seq - 1, 1));

    var valid = nodes.every((n, i) =>
            dependencyDict[n].dependsOn.every(m => nodes.indexOf(m) <= i) &&
            dependencyDict[n].dependable.every(m => nodes.indexOf(m) >= i)
        );

    console.log(valid);
    if (valid) nodes.forEach((node, i) => itemList[node].seq = i + 1);
    console.log(nodes);
    console.log(itemList);
}

var dependencyDict = {
        item1: {dependsOn: [], dependable: ['item3']},
        item2: {dependsOn: [], dependable: []},
        item3: {dependsOn: ['item1'], dependable: ['item4']},
        item4: {dependsOn: ['item4'], dependable: []}
    },
    itemList  = {
        item1: { name: 'item1', seq: 1, dep: dependencyDict['item1'] },
        item2: { name: 'item2', seq: 2, dep: dependencyDict['item2'] },
        item3: { name: 'item3', seq: 3, dep: dependencyDict['item3'] },
        item4: { name: 'item4', seq: 4, dep: dependencyDict['item4'] }
    };

move('item3', 1);
move('item3', 2);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2012-02-03
    • 2010-10-14
    • 1970-01-01
    • 2010-12-19
    相关资源
    最近更新 更多