I
I
iSnaker2021-03-27 20:58:05
JavaScript
iSnaker, 2021-03-27 20:58:05

JavaScript - how to check if an object has circular references?

I ran into such a task during an interview and could not approach it correctly. It is necessary to determine if the specified object has cyclic dependencies. As the closest example, dependencies in node modules are given.
So, the task itself: write a hasCircularDepengency(entrypoint, data) function that will return true / false for the data = object

const data = {
    "index.js" : ['foo.js'],
    "foo.js"   : ['baz.js', 'lol.js'],
    "baz.js"   : ['bar.js', 'lem.js'],
    "bar.js"   : ['baz.js', 'k.js'],
};


The function is called with parameters hasCircularDepengency("index.js",data) and in theory should return false, since the baz.js pointer has the bar.js dependency, and bar.js has the opposite baz.js dependency.
The algorithm is clear - you need to make a list of paths already passed, and if you suddenly come across a pointer that appears twice in the list, then there is a cyclic dependency and the result will be false.
How exactly to implement this with the help of recursion - I'm fighting for the third day, so far to no avail.

I ask for help in the analysis of the approach.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
W
Wataru, 2021-03-27
@wataru

Search in depth .
It is necessary to maintain a list / set of already visited vertices and currently visited ones (those in the stack). When visiting a vertex in a recursive function, place it in the currently visited set. When returning from the function, move the vertex to the set already visited. In the function, go through all the edges, if they lead to the currently visited vertex - you have found a cycle. If the edge leads to an already visited one, ignore it. If the edge leads to an unvisited vertex, recursively run from it.

D
Daniil Popov, 2021-03-28
@groog

I wrote an illustration of how to organize such a bypass and see what happens in each step. If you wish and with a little effort, you can convert the function to the conditions of the problem

The code

const data = {
  "index.js": ["foo.js"],
  "foo.js": ["baz.js", "lol.js"],
  "baz.js": ["bar.js", "lem.js"],
  "bar.js": ["baz.js", "k.js"]
};

function searchCircularDepengency(entry = "index.js", path = []) {
  const branch = data[entry];
  const newPath = [...path, entry];

  console.log("Path", newPath);

  // Если есть вложенные элементы,
  if (branch) {
    // проверить каждый
    branch.forEach((nextEntry) => {
      // на предмет прохожения ранее,
      if (path.includes(nextEntry)) {
        console.warn(
          "Found Circular Depengency " + nextEntry + " in " + entry,
          path
        );
        // если нет идти глубже
      } else {
        searchCircularDepengency(nextEntry, newPath);
      }
    });
  } else {
    console.log("Branch complite. All OK!");
  }
}

console.log(searchCircularDepengency());


in the sandbox

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question