使用 javascript / node 对相互依赖的对象内联进程进行排序

如何解决使用 javascript / node 对相互依赖的对象内联进程进行排序

我已经为此纠结了很长一段时间,希望能在这里得到一些支持我有一个包含多个对象的数组。

每个对象都代表一个由输入和输出组成的子过程组成的生产过程。这些过程是在线运行的。意思是,一个进程的输出将成为另一个进程的输入。但是,我不知道按哪个顺序。

我正在尝试找出主要进程需要运行的顺序。我们的系统无法告诉我,现在我有 5000 个相互依赖的进程需要排序。

这里是数组格式化方式的示例。如您所见,输入有一个原点标志。至少我们知道输入是从仓库中获取还是在上游某处生产。如果我手动排序,顺序将是 Process3,然后是 Process 2,然后是 Process 1。Process 1 需要带有 id="ID3" 的材料作为输入,它是在 process 2 中生成的(在 subprocess 2 下)。而流程 2 需要流程 3 中产生的材料“ID5”。有人知道如何解决这个噩梦吗?

非常感谢!!!

[
  {
    processID: "1",subprocesses: [
      {
        subprocessID: "1",outputs: [
          {
            id: "ID1",name: "alpha",ratio: "1",},],inputs: [
          {
            type: "rawMaterial",id: "ID2",ratio: "0.7623",{
            type: "processOutput",id: "ID3",ratio: "0.6552",{
    processID: "2",outputs: [
          {
            id: "ID22",name: "beta)",inputs: [
          {
            type: "processOutput",id: "ID5",ratio: "0.0034",{
        subprocessID: "2",outputs: [
          {
            id: "ID3",name: "gamma",id: "ID10",{
    processID: "3",outputs: [
          {
            id: "ID5",name: "omega",id: "ID111",ratio: "0.3018",]

解决方法

正如我在评论中所说,您似乎遇到的是图论问题:-)

  • 整个thingamabob 是一个有向无环图——或者在这种情况下,基本上是一个依赖树。
  • 每个子流程作为图中的一个节点。
  • 边缘从输出资源的进程指向需要这些资源的进程。
  • 图的拓扑顺序是完成过程所需的顺序。

此解决方案需要 toposort 包来进行繁重的图形提升。

const processes = require("./processes"); // Data from original post
const toposort = require("toposort");

const processInputs = {}; // Inputs required per subprocess
const outputIdToProcessIds = {}; // Map output IDs to processes that create them
const predecessorMap = {}; // Map process IDs to the node(s) that need to run immediately before

// Step 1: massaging the input data.

// Loop over top-level processes...
processes.forEach((proc) => {
  // and each subprocess within.
  proc.subprocesses.forEach((subproc) => {
    // Compute an unique ID for the process-subprocess.
    const procId = `${proc.processID}/${subproc.subprocessID}`;
    // Add it to our map of predecessors; this way each process,whether it's needed or not,// is in the predecessor map.
    // This also adds a "virtual" "start" predecessor for each node; it's not strictly necessary.
    predecessorMap[procId] = ["start"];

    // Gather the required inputs for each process.
    subproc.inputs.forEach((input) => {
      (processInputs[procId] = processInputs[procId] || []).push(input);
    });

    // Gather an inverse mapping of output ids to processes that create them.
    subproc.outputs.forEach((output) => {
      (outputIdToProcessIds[output.id] = outputIdToProcessIds[output.id] || []).push(procId);
    });
  });
});

// Step 2: massaging the processed data.

// Loop over the processes that actually do need inputs.
Object.entries(processInputs).forEach(([pid,inputs]) => {
  // For each input...
  inputs.forEach((input) => {
    // ... find the process IDs that can create these outputs.
    const pidsForInput = outputIdToProcessIds[input.id] ?? [];
    if (!pidsForInput.length) {
      console.warn(`There is no process that would output ${input.id} required by ${pid}`);
    } else {
      // Push the first one of them into the predecessors list for this process.
      // This might need special handling if it's possible for a resource to be output
      // by multiple processes.
      predecessorMap[pid].push(pidsForInput[0]);
    }
  });
});

// Step 3: creating graph data.
const allEdges = []; // All edges in from-to order
// Walk over the predecessor map...
Object.entries(predecessorMap).forEach(([to,froms]) => {
  // and each predecessor of each node,and push them into the full list of edges
  froms.forEach((from) => allEdges.push([from,to]));
});

console.log(allEdges);

// Step 4: sort!
// Run the toposort and print the order!
toposort(allEdges).forEach((node) => {
  console.log(node);
});

由于原始帖子中的数据不完整,程序会就此向您发出警告,但不会完全失败。

当然,解决方案也是不完整的。

输出为:

There is no process that would output ID2 required by 1/1
There is no process that would output ID10 required by 2/2
There is no process that would output ID111 required by 3/1

接着是图的边

[
  [ 'start','1/1' ],[ '2/2',[ 'start','2/1' ],[ '3/1','2/2' ],'3/1' ]
]

最后是需要的“执行顺序”(使用虚拟“开始”节点):

start
2/2
1/1
3/1
2/1

所以,顺序是:

  • 流程 2 子流程 2 已完成
  • 流程 1 子流程 1 已完成
  • 流程 3 子流程 1 已完成
  • 流程 2 子流程 1 已完成

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?