簡體   English   中英

使用 DAG 對象將一維數組轉換為二維數組

[英]Convert a Single Dimension Array to Two Dimensional Array with DAG Objects

我們正在構建一個應用程序,客戶端將能夠在其中構建工作流,表示為DAG 當在屏幕上輸出時,它將如下所示:

DAG 工作流顯示

上圖使用二維數組輸出到屏幕,模型如下所示:

const dag = [
  [
    { id: 1, parentId: 0 }
  ],
  [
    { id: 2, parentId: 1 },
    { id: 3, parentId: 1 }
  ],
  [
    { id: 6, parentId: 2 },
    { id: 4, parentId: 3 },
    { id: 5, parentId: 3 }
  ],
]

二維數組模型允許我遍歷它並在屏幕上輸出每一行; 所以在第一項dag模型是第一行與一個節點,在第二項dag模型是在第二排具有兩個節點,依此類推。

這部分有效,我什至想出了如何動態地將節點添加到圖形中。 我遇到問題的部分是從一維數組創建二維數組。 圖的數據將發送到服務器並作為一維數組從服務器返回,如下所示:

const items = [
  { id: 1, parentId: 0 },
  { id: 2, parentId: 1 },
  { id: 3, parentId: 1 },
  { id: 4, parentId: 3 },
  { id: 5, parentId: 3 },
  { id: 6, parentId: 2 },
]

我需要將這個items數組轉換成上面的dag多維數組。

這是我到目前為止所擁有的:

// this is the end array, (two dimensions [][]), that will be used to draw the graph
const dag = [];

// this will create the first row of the array, with all the items that have a parentId of 0
const newRow = items
  .filter((item) => item.parentId === 0)
  .reduce((arr, item) => {
    arr.push(item);
    return arr;
  }, []);
dag.push(newRow);

// Now I'm trying to move down the graph from top to bottom
dag.forEach((row) => {
  // get the list of item IDs that are in this row
  const itemIdsInRow = row.reduce((prev, row) => {
    prev.push(row.id);
    return prev;
  }, []);

  // use the itemIdsInRow to get the items from the single dimensional array that will go in the next row
  const itemsForNextRow = itemIdsInRow.reduce((itemsArr, id) => {
    const nextItems = items.filter((item) => item.parentId === id);
    itemsArr.push(...nextItems);
    return itemsArr;
  }, []);

  // push the new row onto the two dimension array
  dag.push(itemsForNextRow);
});

這適用於dag的前兩行。 這說得通; 當我繼續使用dag模型時, forEach不允許我繼續通過循環來構建第三行。 如果我在前兩行的forEach之前啟動dag數組,我可以正確構建第三行,因此構建dag的算法非常接近那里。

如果您對如何解決這個問題有任何意見或想法,我將不勝感激。 謝謝!

編輯

我們也有必要現在每個項目的parentId是數組parentId秒。 這是因為兩個分支可以在一個點合並,所以一個節點可能有兩個(或更多)父節點。 想象在上圖中,節點 4 和 5 在它們下面有一個子節點,它們每個都連接到該子節點。 這是代碼中的起始數組和結果數組:

const start = [
  { isYesPath: undefined, name: 'Step 1', parentIds: [0], stepId: 1, type: DagBranchType.Normal },
  { isYesPath: undefined, name: 'Step 2', parentIds: [1], stepId: 2, type: DagBranchType.IfElse },
  { isYesPath: true, name: 'Step 3', parentIds: [2], stepId: 3, type: DagBranchType.Normal },
  { isYesPath: false, name: 'Step 4', parentIds: [2], stepId: 4, type: DagBranchType.Normal },
  { isYesPath: undefined, name: 'Step 5', parentIds: [3, 4], stepId: 5, type: DagBranchType.Normal },
]

const result = [
  [{ isYesPath: undefined, name: 'Step 1', parentIds: [0], stepId: 1, type: DagBranchType.Normal }],
  [{ isYesPath: undefined, name: 'Step 2', parentIds: [1], stepId: 2, type: DagBranchType.IfElse }],
  [
    { isYesPath: true, name: 'Step 3', parentIds: [2], stepId: 3, type: DagBranchType.Normal },
    { isYesPath: false, name: 'Step 4', parentIds: [2], stepId: 4, type: DagBranchType.Normal }
  ],
  [{ isYesPath: undefined, name: 'Step 5', parentIds: [3, 4], stepId: 5, type: DagBranchType.Normal }]
]

您可以通過使用forEachfilter方法創建一個遞歸函數並傳遞父 ID 和當前級別來獲得所需的結果。 然后,您可以使用 level 按索引添加到結果數組中。

 const items = [{"id":1,"parentId":0},{"id":2,"parentId":1},{"id":3,"parentId":1},{"id":4,"parentId":3},{"id":5,"parentId":3},{"id":6,"parentId":2}] const result = [] const modify = (data, pid = 0, level = 0) => data .filter(({ parentId }) => parentId === pid) .forEach(e => { if (!result[level]) result[level] = [e] else result[level].push(e); modify(data, e.id, level + 1) }) modify(items) console.log(result);

已經有幾個解決方案,但是我想建議一個沒有突變的解決方案。

 const items = [ { id: 1, parentId: 0 }, { id: 2, parentId: 1 }, { id: 3, parentId: 1 }, { id: 4, parentId: 3 }, { id: 5, parentId: 3 }, { id: 6, parentId: 2 }, ]; const partition = predicate => list => [ list.filter (predicate), list.filter (x => !predicate (x)), ]; const inLevel = nth => original => item => { if (nth < 0) return false; const parent = original.find (({id}) => id === item.parentId); return !parent ? nth === 0 : inLevel (nth - 1) (original) (parent); }; const buildTree = (original) => (list, nth = 0) => { const [currentLevel, rest] = partition (inLevel (nth) (original)) (list); return rest.length > 0 ? [ currentLevel, ...buildTree (original) (rest, nth + 1) ] : [ currentLevel ]; } console.log (buildTree (items) (items));

一種可能的解決方案如下。 我不確定這是最好的方法還是最有效的方法,但它確實有效。 基本上,我會跟蹤items數組中的哪些對象已被使用,當它們使用時,我將它們推送到usedItems數組。 我循環了將新行添加到dag模型的代碼,而usedItems.length !== items.length

const items = [
  { id: 1, parentId: 0 },
  { id: 2, parentId: 1 },
  { id: 3, parentId: 1 },
  { id: 4, parentId: 3 },
  { id: 5, parentId: 3 },
  { id: 6, parentId: 2 },
];
// As items are used, push them on this array
const usedItems = [];

// this is the end array, (two dimensions [][]), that will be used to draw the graph
const dag = [];

// this will create the first row of the array, with all the items that have a parentId of 0
const newRow = items
  .filter((item) => item.parentId === 0)
  .reduce((arr, item) => {
    arr.push(item);
    return arr;
  }, []);
dag.push(newRow);
usedItems.push(...newRow);

// go until the usedItems array is the same length as the original items array
while (usedItems.length !== items.length) {
  // get the list of item IDs that are in this row
  const row = dag[dag.length - 1];
  const itemIdsInRow = row.reduce((prev, row) => {
    prev.push(row.id);
    return prev;
  }, []);

  // use the itemIdsInRow to get the items from the single dimensional array that will go in the next row
  const itemsForNextRow = itemIdsInRow.reduce((itemsArr, id) => {
    const nextItems = items.filter((item) => item.parentId === id);
    itemsArr.push(...nextItems);
    return itemsArr;
  }, []);

  // push the new row onto the two dimension array
  dag.push(itemsForNextRow);
  usedItems.push(...itemsForNextRow);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM