Ad

How Can I Sort A Javascript Array Of Objects That Specify Prerequisites Between Them?

- 1 answer

I have an array of objects that determine which ones should be showed first. An example of this array would be:

[
    {
        "id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870",
        "prerequisites_ids": [
            "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"
        ]
    },
    {
        "id": "ef7d2415-808f-4efc-939e-2692f38a5ee7",
        "prerequisites_ids": [
            "74e41a2c-e74e-4016-bb2c-f2e84c04fe92"
        ]
    },
    {
        "id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92",
        "prerequisites_ids": []
    },
    {
        "id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1",
        "prerequisites_ids": [
            "ef7d2415-808f-4efc-939e-2692f38a5ee7"
        ]
    }
]

How could I sort it to get this?

[
    {
        "id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92",
        "prerequisites_ids": []
    },
    {
        "id": "ef7d2415-808f-4efc-939e-2692f38a5ee7",
        "prerequisites_ids": [
            "74e41a2c-e74e-4016-bb2c-f2e84c04fe92"
        ]
    },
    {
        "id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1",
        "prerequisites_ids": [
            "ef7d2415-808f-4efc-939e-2692f38a5ee7"
        ]
    },
    {
        "id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870",
        "prerequisites_ids": [
            "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"
        ]
    }
]

I have tried creating a custom function:

export function comparePrerequisites(a, b) {
  if (!a.prerequisites_ids) {
    return -1
  }
  if (a.prerequisites_ids.includes(b.id)) {
    return 1;
  }
}
data.sort(comparePrerequisites)

but does not seem to work. Thanks in advance!

Ad

Answer

We have here the requirements for a topological sort. This is not a job for the sort method. Instead you can use recursion (a DFS traversal) to drill down to a dependency that is already collected, or to a leaf (no dependencies).

Here is an implementation:

function topologicalSort(tasks) {
    const visited = new Set;
    const taskMap = new Map(tasks.map(task => [task.id, task]));
    
    function dfs(tasks) {
        for (let task of tasks) {
            if (!visited.has(task.id)) {
                dfs(task.prerequisites_ids.map(id => taskMap.get(id)));
            }
            visited.add(task);
        }
    }
    
    dfs(tasks);
    return [...visited];
}

// Demo on your example:
let tasks = [{"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870","prerequisites_ids": ["2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"]},{"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7","prerequisites_ids": ["74e41a2c-e74e-4016-bb2c-f2e84c04fe92"]},{"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92","prerequisites_ids": []},{"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1","prerequisites_ids": ["ef7d2415-808f-4efc-939e-2692f38a5ee7"]}];
console.log(topologicalSort(tasks));

Ad
source: stackoverflow.com
Ad