Reputation: 4452
I am trying to search through a deeply nested array and find if a key exists anywhere inside. I have written up a piece of code which does the traversal, but because it is not recursive (only self calling) it cannot return whether or not it has found anything. It just returns undefined
since it reaches the end of the function on one of passes.
I was wondering if there was a way I could do this which would allow me to return true
on the first occurrence of a specific key.
Here is a JS bin of what I have been working with so far:
https://jsbin.com/qaxuwajuso/edit?js,console
And here is a direct paste of the code from the above example:
function traverse(item, key) {
if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
// Object
for (let itemKey in item) {
if (itemKey === key) {
// Is it possible to return true and break out of the function here?
console.log('found the key: ' + itemKey + ' With value: ' + item[itemKey]);
}
traverse(item[itemKey], key);
}
} else if (Array.isArray(item)) {
// Array
for (let i = 0; i < item.length; ++i) {
traverse(item[i], key);
}
}
}
Any help would be greatly appreciated. Thank you for your time!
Upvotes: 1
Views: 541
Reputation: 8088
My variant:
const data = [{id: '2144d998-4c33-4b03-93d2-f6c675b24508', element: 'div', props: {className: 'testing', name: [{first: 'John', last: {statePath3: 'lastName', anArray: [{anObject: {anotherArray: [{doesItWork: {statePath1: 'hello',},},],},},],},}, {first: 'Jane', last: {statePath: 'lastName',},},],}, children: 'hi',},];
function traverse(data, find) {
for (let k in data) {
let deepHaveKey = typeof data[k] === 'object' && traverse(data[k], find)
if (find === k || deepHaveKey)
return true
}
return false
}
console.log(traverse(data, 'statePath')); // true
console.log(traverse(data, 'state')); // false
Upvotes: 0
Reputation: 122047
You could use for...in
and store result in one var and then check that var before you call function again and break loop if value is found.
const data = [{"id":"2144d998-4c33-4b03-93d2-f6c675b24508","statePath":"div","props":{"className":"testing","name":[{"first":"John","last":{"statePath":"lastName","anArray":[{"anObject":{"anotherArray":[{"doesItWork":{"statePath":"hello"}}]}}]}},{"first":"Jane","last":{"statePath":"lastName"}}]},"children":"hi"}]
function traverse(item, key) {
let result = false;
for (var i in item) {
if (i == key) {
result = true;
break;
}
if (typeof item[i] == 'object' && !result) {
result = traverse(item[i], key)
}
}
return result
}
console.log(traverse(data, 'statePath'))
Upvotes: 1
Reputation: 22247
Sure you just need to return a flag of some kind to trigger the loops to stop
/*
* I am trying to search the following json array for any occurance of the key "statePath".
* In a perfect world I would be able to find the first occurance, and return true from the
* function.
*
* The following data is not real, I was just trying to write as much nested stuff as possible
* to test that it traverses as far as needed.
*/
const data = [
{
id: '2144d998-4c33-4b03-93d2-f6c675b24508',
element: 'div',
props: {
className: 'testing',
name: [
{
first: 'John',
last: {
statePath: 'lastName',
anArray: [
{
anObject: {
anotherArray: [
{
doesItWork: {
statePath: 'hello',
},
},
],
},
},
],
},
},
{
first: 'Jane',
last: {
statePath: 'lastName',
},
},
],
},
children: 'hi',
},
];
function traverse(item, key) {
if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
// Object
for (let itemKey in item) {
if (itemKey === key) {
console.log('found the key: ' + itemKey + ' With value: ' + item[itemKey]);
// not sure what you want the end "return" of the func to be, I'm returning the value. You could return true here instead, you could return a reference to the parent object, lots of possibilities
return item[itemKey];
}
var found = traverse(item[itemKey], key);
if (found !== undefined) return found;
// otherwise keep looking
}
} else if (Array.isArray(item)) {
// Array
for (let i = 0; i < item.length; ++i) {
var found = traverse(item[i], key);
if (found !== undefined) return found;
}
}
}
var value = traverse(data, 'statePath');
console.log("value is " + value);
Upvotes: 2