Say I have a Javascript data structure such as:
var data = {
id: '5551212',
children: [
{id: '5551213'},
{id: '5551214'},
{
id: '5551215',
children: [
{id: '5551213'},
{id: '5551212'} // <--- I want to detect THIS one! It's a recursive entry.
// or a similar occurrence anywhere in the tree.
]}
]
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'm looking for a general algorithm to detect a "recursive" item such as the one shown. I find that it's easy enough if the recursive item is just below the "parent" but what if the duplication can occur anywhere?
In this case these are mechanical assembly part numbers. So while it's no problem creating a data structure like this, actually building a recursive assembly is impossible. So I need to find a potential mistake on the user's part before they try to build something impossible.
When searching for algorithms, all I'm getting are recursive programming examples and discussions or here on StackOverflow most questions seem to be about how to create such a recursive structure.
I'm working in Javascript w/ JQuery but I'm looking for an applicable algorithm here, not necessarily an implementation.
3 Answers 3
How to do it:
- Check if parents of the current subtree contain its root id
- If no, and subtree has children - check their subtrees recursively
- If there are no children - return false
And here is the code:
function isRecursive(tree, parents){
if (parents.indexOf(tree.id) !== -1){
return true;
} else if (tree.children) {
return tree.children.some(child => isRecursive(child, [tree.id].concat(parents)));
}
return false;
}
isRecursive(data, []);
It can be improved by replacing array with set but I wanted to make it as compatible as possible.
2 Comments
children: [{id:X},{id:X}]Use this:
var arr = []
function detectRecursive(object){
var x
for(x in object){
if(arr.indexOf([x,object[x]])==-1){
arr.push([x,object[x]])
var tmp = {}
if(typeof object[x] == typeof tmp){
detectRecursive(object[x])
}
}
}
}
This loops over the keys and values of the array
3 Comments
You could use a Map to keep track of the "path" keyed by each id value. Then when you find an id is already in that Map, you could push this pair of paths to a results array.
Here is how that would work:
function collectDuplicates(data) {
const map = new Map,
dups = [];
function recurse(data, path) {
if (map.has(data.id)) {
dups.push([data.id, map.get(data.id), path]);
} else {
map.set(data.id, path);
}
(data.children || []).forEach( (child, i) => {
recurse(data.children[i], path + '.children[' + i + ']');
})
}
recurse(data, 'data');
return dups;
}
// Sample
var data = {
id: '5551212',
children: [
{id: '5551213'},
{id: '5551214'},
{
id: '5551215',
children: [
{id: '5551213'},
{id: '5551212'}
]
}
]
};
console.log(collectDuplicates(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
In this snippet I built the path in a notation that corresponds to the object notation to get to the two objects that have the same id property, but you could of course use a completely different notation or reference system.
JSON.stringify()? What should occur if the value is found?JSON.stringify()replacerfunction is recursive and can be used to match or remove properties from the resulting JavaScript object remove object from nested array.RegExpcould also be used to match duplicate values. It is not clear what should occur if duplicate property, value pairs occur.