Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
List all duplicate values in a nested JavaScript object
When working with nested JavaScript objects, you may need to find duplicate values that appear at different levels of nesting. This tutorial shows how to recursively search through a nested object and identify all duplicate values.
Problem Statement
Consider a nested object containing pet information:
const pets = {
owner1: 'Frank',
owner2: 'Curly',
owner3: 'Maurice',
dogs: {
terriers: {
name1: 'Fido',
name2: 'Woofy',
name3: {
goodDog: 'Frank',
badDog: 'Judas',
}
},
poodles: {
name1: 'Curly',
name2: 'Fido',
},
},
};
console.log(pets);
{
owner1: 'Frank',
owner2: 'Curly',
owner3: 'Maurice',
dogs: {
terriers: { name1: 'Fido', name2: 'Woofy', name3: [Object] },
poodles: { name1: 'Curly', name2: 'Fido' }
}
}
We need to find values that appear multiple times across all levels: 'Frank', 'Curly', and 'Fido'.
Solution: Recursive Search Function
Here's a function that recursively traverses the object and tracks value occurrences:
const pets = {
owner1: 'Frank',
owner2: 'Curly',
owner3: 'Maurice',
dogs: {
terriers: {
name1: 'Fido',
name2: 'Woofy',
name3: {
goodDog: 'Frank',
badDog: 'Judas',
}
},
poodles: {
name1: 'Curly',
name2: 'Fido',
},
},
};
const recursiveSearch = (obj, map = {}, res = []) => {
Object.keys(obj).forEach(key => {
if(typeof obj[key] === "object"){
return recursiveSearch(obj[key], map, res);
};
map[obj[key]] = (map[obj[key]] || 0) + 1;
if(map[obj[key]] === 2){
res.push(obj[key]);
}
});
return res;
};
console.log(recursiveSearch(pets));
[ 'Frank', 'Curly', 'Fido' ]
How It Works
The algorithm uses three key components:
- map: Tracks how many times each value appears
- res: Stores duplicate values (added when count reaches 2)
- Recursion: Handles nested objects by calling itself
Step-by-Step Process
Let's trace through the execution with a simpler example:
const simpleObj = {
a: 'hello',
b: 'world',
nested: {
c: 'hello',
d: 'test'
}
};
const findDuplicates = (obj, map = {}, res = []) => {
Object.keys(obj).forEach(key => {
console.log(`Processing key: ${key}, value: ${obj[key]}`);
if(typeof obj[key] === "object"){
console.log(`Found nested object, recursing...`);
return findDuplicates(obj[key], map, res);
};
map[obj[key]] = (map[obj[key]] || 0) + 1;
console.log(`Value '${obj[key]}' count: ${map[obj[key]]}`);
if(map[obj[key]] === 2){
res.push(obj[key]);
console.log(`Duplicate found: ${obj[key]}`);
}
});
return res;
};
console.log("Final duplicates:", findDuplicates(simpleObj));
Processing key: a, value: hello Value 'hello' count: 1 Processing key: b, value: world Value 'world' count: 1 Processing key: nested, value: [object Object] Found nested object, recursing... Processing key: c, value: hello Value 'hello' count: 2 Duplicate found: hello Processing key: d, value: test Value 'test' count: 1 Final duplicates: [ 'hello' ]
Alternative Implementation
Here's a cleaner version that separates concerns:
function findDuplicatesInObject(obj) {
const valueCount = {};
function traverse(current) {
Object.values(current).forEach(value => {
if (typeof value === 'object' && value !== null) {
traverse(value);
} else {
valueCount[value] = (valueCount[value] || 0) + 1;
}
});
}
traverse(obj);
return Object.keys(valueCount).filter(value => valueCount[value] > 1);
}
const pets = {
owner1: 'Frank',
owner2: 'Curly',
owner3: 'Maurice',
dogs: {
terriers: {
name1: 'Fido',
name2: 'Woofy',
name3: {
goodDog: 'Frank',
badDog: 'Judas',
}
},
poodles: {
name1: 'Curly',
name2: 'Fido',
},
},
};
console.log(findDuplicatesInObject(pets));
[ 'Frank', 'Curly', 'Fido' ]
Conclusion
Finding duplicates in nested objects requires recursive traversal to visit all values at every level. The key is maintaining a count map and identifying when values appear more than once across the entire object structure.
