Search and find numbers starting with particular number - javascript

I was trying to create a search plugin for my custom table plugin.
In my search I use
function getObjects(obj, key, val, path) {
for (var prop in obj) {
if (prop == key && obj[key].toLowerCase().match(val)) {
result.push(passName);
matchFlag = 1;
}
}
}
where
obj -> JSON
key -> search filter
val -> search keyword will be like '^m'
This works as long as the search keyword is a string/character.
How to handle scenario where search keyword is numeric? I tried using indexOf also.

Just make the value a String by concatenating an empty String:
function getObjects(obj, key, val, path) {
var value = val + "";
for (var prop in obj) {
if (prop == key && obj[key].toLowerCase().match(value)) {
result.push(passName);
matchFlag = 1;
}
}
}

The issue was from json, fixed it by adding toString()
function getObjects(obj, key, val, path) {
for (var prop in obj) {
if (prop == key && obj[key].toString().toLowerCase().match(val)) {
result.push(passName);
matchFlag = 1;
}
}
}

You can use this javascript library; DefiantJS (defiantjs.com) which extends the global object JSON with the method "search". Using this method, you can search a JSON structure with XPath expressions like this:
var data = [
{
"name": "Tom",
"age": 27
},
{
"name": "Lisa",
"age": 22
}
],
res1 = JSON.search( data, '//*[name = "Lisa"]' ),
res2 = JSON.search( data, '//*[age = 27]' ),
res3 = JSON.search( data, '//name[contains(.,"om")]/..' );
console.log( res1[0].age );
// 22
console.log( res2[0].name );
// Tom
console.log( res3[0] );
// { "name": "Tom", "age": 27 }
Here is a working fiddle:
http://jsfiddle.net/hbi99/2C8Ac/

Related

Compare key values within object for duplicate

I have an object:
myObj = {
attendent-0-id:"123",
attendent-0-name:"Bob Smith",
attendent-1-id:"1234",
attendent-1-name:"Alex Smith",
attendent-2-id:"123",
attendent-2-name:"Charlie Smith",
attendent-maxGuest:1,
attendent-party-name:"",
}
I need to create a loop that go through myObj and find all the id's and then compares them for duplicates. So in this case it would log an error because attendent-0-id is equal to attendent-2-id.
If I do find duplicates I need to set a flag to true;
I have tried a bunch of things and am just stuck at this point. Thanks for any help.
In your case you can go through myObj using Object.keys() via:
for (const key of Object.keys(obj))
use a plain object as a map to store the previous values of the ids:
const map = {};
use a regex pattern to make sure only the specific ids are evaluated:
const pattern = /^attendent-\d+-id$/;
and then with the help of the map, log the error on duplicate ids:
if (value in map) {
console.error(`${map[value]} is equal to ${key}, which is ${value}`);
}
Example:
const myObj = {
'attendent-0-id': "123",
'attendent-0-name': "Bob Smith",
'attendent-1-id': "1234",
'attendent-1-name': "Alex Smith",
'attendent-2-id': "123",
'attendent-2-name': "Charlie Smith",
'attendent-maxGuest': 1,
'attendent-party-name': "",
};
function errorOnDuplicateIds(obj) {
const map = {};
const pattern = /^attendent-\d+-id$/;
for (const key of Object.keys(obj)) {
if (pattern.test(key)) {
const value = obj[key]
if (value in map) {
console.error(`${map[value]} is equal to ${key}, which is ${value}`);
} else {
map[value] = key
}
}
}
}
errorOnDuplicateIds(myObj);
const ids = []; // keep track of found ids
Object.keys(myObj).forEach(key => { // iterate over all properties of myObj
// check if property name is in format "attendent-" *some number* "-id"
if (/^attendent-\d+-id$/.test(key)) {
// check if the id has already been found
if (ids.findIndex(id => id === myObj[key]) !== -1) {
console.log('error');
} else {
ids.push(myObj[key]);
}
}
});
You can use Object.entries and a Map (keyed by value) for this:
var myObj = {"attendent-0-id":"123","attendent-0-name":"Bob Smith","attendent-1-id":"1234","attendent-1-name":"Alex Smith","attendent-2-id":"123","attendent-2-name":"Charlie Smith","attendent-maxGuest":1, "attendent-party-name":""};
var dupes = [...Object.entries(myObj).reduce(
(map, [key,val]) => map.set(val, (map.get(val) || []).concat(key)),
new Map
).values()].filter(keys => keys.length > 1);
console.log(dupes);
This solution does not give any particular meaning to the format of the keys.
Having said that, your object structure looks suspicious of bad design: you should not have enumerations in your object keys. For that you should use arrays.
Object.values(myObj) will create an array of all values and then you can use any way to find duplicate elements in that array.
var myValues = Object.values(myObj); //This will create an array of all values
var uniq = myValues.map((val) => {
return {count: 1, val: val}
}).reduce((a, b) => {
a[b.val] = (a[b.val] || 0) + b.count
return a
}, {});
var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1)
if (duplicates.length) {
return true;
} else {
return false;
}
My first advice would be to redefine your object to something more flexible.
let myObject = {
attendants : [
{
id: "123",
name: "Bob Smith"
},
{
id: "456",
name: "Alex Smith"
},
{
id: "768",
name: "Charlie Smith"
},
],
maxGuest: 1,
partyName: ""
};
This will allow you to iterate the attendants.
for (var attendant in myObject.attendants){
doSomething(attendant.id, attendant.name);
}
You can also sort the attendant:
// Sort by id
myObject.attendants.sort(function(left, right){
return left.value - right.value;
});
// Sort by name
myObject.attendants.sort(function (left, right){
var leftName = left.name.toLowerCase();
var rightName = right.name.toLowerCase();
if (leftName < rightName) return -1;
if (leftName > rightName) return 1;
return 0;
});
Now, lets assume you don't have a choice. Then it gets complicated.
You need to create (or modify an existent) a sort algorithm so it can use keys that are generated as:
myObject[`attendent-${index}-id`]
myObject[`attendent-${index}-name`]
and keep the pair

Nested Json Access Value

Here is my Json-String:
{
"batchcomplete":"",
"query":{
"pages":{
"104352":{
"pageid":104352,
"ns":0,
"title":"student"
}
}
}
}
I want to access tha first number, in this example "103452", not the on after pageid, although they always should be the same.
I tried the following until know, but don´t get why it wont work.
JSONName.query.pages;
it always returns me Object object.
Assuming you have a JavaScript object you can get the keys of an object which would contain your string.
const obj = {
"batchcomplete": "",
"query": {
"pages": {
"104352": {
"pageid": 104352,
"ns": 0,
"title": "student"
}
}
}
}
// Get the keys for pages
const keys = Object.keys(obj.query.pages);
// Print out the first key
console.log(keys[0]);
Might be easier to find it during the parsing:
var n, j = '{"batchcomplete":"","query":{"pages":{"104352":{"pageid":104352,"ns":0,"title":"student"}}}}';
var result = JSON.parse(j, (key, value) => (n = n || +key, value));
console.log( n ); console.log( result );

Javascript, how to split key with dot to recovery json structure

I have a json, it is
{
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.sub1.sub2": "content4"
}
I want to recovery the structure, like
{
"prop1": {
"sub1": {
"sub2" : "content1",
"sub3" : "content2"
}
},
"prop2": {
"sub1": {
"sub2" : "content3"
}
},
"prop3": {
"sub1": {
"sub2" : "content4"
}
}
}
I split the key with dot to get each key.
for (var key in json) {
var keySplit = key.split('.');
// Todo: recovery the structure
}
But not found a good solution.
Is anyone has solution?
You can use Array#reduce method.
var obj = {
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.sub1.sub2": "content4"
};
// iterate over the property names
Object.keys(obj).forEach(function(k) {
// slip the property value based on `.`
var prop = k.split('.');
// get the last value fom array
var last = prop.pop();
// iterate over the remaining array value
// and define the object if not already defined
prop.reduce(function(o, key) {
// define the object if not defined and return
return o[key] = o[key] || {};
// set initial value as object
// and set the property value
}, obj)[last] = obj[k];
// delete the original property from object
delete obj[k];
});
console.log(obj);
Answer by Pranav C Balan is right for the question you asked. But JSON's might not be as simple as you have mentioned above and can have array's also and few keys might not have "." in them. To handle all these cases you can use the following one.
var obj = {
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.0.sub2": "content4"
};
function createJSONStructure(obj) {
Object.keys(obj).forEach(function(k) {
var prop = k.split('.'); //split on . to get elements
if(prop.length >1){ //If there is no dot just key the value as is.
let data = obj;//Copy the default object to data in each loop
for(i=0;i<prop.length-1;i++){
if(data[prop[i]]){ // Check if the key exists
if((prop[i+1].match(/^\d+$/) && !Array.isArray(data[prop[i]])) // Check if the next key is a digit and the object we have is a JSON
|| (!prop[i+1].match(/^\d+$/) && Array.isArray(data[prop[i]]))){ // Check if the next key is not a digit and the object we have is a Array
throw new Error("Invalid header data"); //If any of the above cases satisfy we cannot add the key so we can throw an error.
}
data = data[prop[i]]; // If key exisits make the data variable as the value of the key
}else {
if(prop[i+1].match(/^\d+$/)){ //If the key is not available see if the next parameter is a digit or string to decide if its array or string
data[prop[i]] = [];
}else{
data[prop[i]] = {};
}
data = data[prop[i]]; //Assign this new object to data
}
};
data[prop[i]] = obj[k]; //Finally add the value to final key
delete obj[k]; // delete the exisiting key value
}
});
return obj;
}
console.log(createJSONStructure(obj));

Accessing elements of JSON object without knowing the key names

Here's my json:
{"d":{"key1":"value1",
"key2":"value2"}}
Is there any way of accessing the keys and values (in javascript) in this array without knowing what the keys are?
The reason my json is structured like this is that the webmethod that I'm calling via jquery is returning a dictionary. If it's impossible to work with the above, what do I need to change about the way I'm returning the data?
Here's an outline of my webmethod:
<WebMethod()> _
Public Function Foo(ByVal Input As String) As Dictionary(Of String, String)
Dim Results As New Dictionary(Of String, String)
'code that does stuff
Results.Add(key,value)
Return Results
End Function
You can use the for..in construct to iterate through arbitrary properties of your object:
for (var key in obj.d) {
console.log("Key: " + key);
console.log("Value: " + obj.d[key]);
}
Is this what you're looking for?
var data;
for (var key in data) {
var value = data[key];
alert(key + ", " + value);
}
{
"d":{
"key1":"value1",
"key2":"value2"
}
}
To access first key write:
let firstKey=Object.keys(d)[0];
To access value of first key write:
let firstValue= d[firstKey];
By using word "b", You are still using key name.
var info = {
"fname": "Bhaumik",
"lname": "Mehta",
"Age": "34",
"favcolor": {"color1":"Gray", "color2":"Black", "color3":"Blue"}
};
Look at the below snippet.
for(key in info) {
var infoJSON = info[key];
console.log(infoJSON);
}
Result would be,
Bhaumik
Mehta
Object {color1: "Gray", color2: "Black", color3: "Blue"}
Don’t want that last line to show up? Try following code:
for(key in info) {
var infoJSON = info[key];
if(typeof infoJSON !== "object"){
console.log(infoJSON);
}
}
This will eliminate Object {color1: “Gray”, color2: “Black”, color3: “Blue”} from showing up in the console.
Now we need to iterate through the variable infoJSON to get array value. Look at the following whole peace of code.
for(key in info) {
var infoJSON = info[key];
if (typeof infoJSON !== "object"){
console.log(infoJSON);
}
}
for(key1 in infoJSON) {
if (infoJSON.hasOwnProperty(key1)) {
if(infoJSON[key1] instanceof Array) {
for(var i=0;i<infoJSON[key1].length;i++) {
console.log(infoJSON[key1][i]);
}
} else {console.log(infoJSON[key1]);}
}
}
And now we got the result as
Bhaumik
Mehta
Gray
Black
Blue
If we use key name or id then it’s very easy to get the values from the JSON object but here we are getting our values without using key name or id.
Use for loop to achieve the same.
var dlist = { country: [ 'ENGLAND' ], name: [ 'CROSBY' ] }
for(var key in dlist){
var keyjson = dlist[key];
console.log(keyjson)
}

Traverse all the Nodes of a JSON Object Tree with JavaScript

I'd like to traverse a JSON object tree, but cannot find any library for that. It doesn't seem difficult but it feels like reinventing the wheel.
In XML there are so many tutorials showing how to traverse an XML tree with DOM :(
If you think jQuery is kind of overkill for such a primitive task, you could do something like that:
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
//called with every property and its value
function process(key,value) {
console.log(key + " : "+value);
}
function traverse(o,func) {
for (var i in o) {
func.apply(this,[i,o[i]]);
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
traverse(o[i],func);
}
}
}
//that's all... no magic, no bloated framework
traverse(o,process);
A JSON object is simply a Javascript object. That's actually what JSON stands for: JavaScript Object Notation. So you'd traverse a JSON object however you'd choose to "traverse" a Javascript object in general.
In ES2017 you would do:
Object.entries(jsonObj).forEach(([key, value]) => {
// do something with key and val
});
You can always write a function to recursively descend into the object:
function traverse(jsonObj) {
if( jsonObj !== null && typeof jsonObj == "object" ) {
Object.entries(jsonObj).forEach(([key, value]) => {
// key is either an array index or object key
traverse(value);
});
}
else {
// jsonObj is a number or string
}
}
This should be a good starting point. I highly recommend using modern javascript methods for such things, since they make writing such code much easier.
function traverse(o) {
for (var i in o) {
if (!!o[i] && typeof(o[i])=="object") {
console.log(i, o[i]);
traverse(o[i]);
} else {
console.log(i, o[i]);
}
}
}
There's a new library for traversing JSON data with JavaScript that supports many different use cases.
https://npmjs.org/package/traverse
https://github.com/substack/js-traverse
It works with all kinds of JavaScript objects. It even detects cycles.
It provides the path of each node, too.
Original Simplified Answer
For a newer way to do it if you don't mind dropping IE and mainly supporting more current browsers (check kangax's es6 table for compatibility). You can use es2015 generators for this. I've updated #TheHippo's answer accordingly. Of course if you really want IE support you can use the babel JavaScript transpiler.
// Implementation of Traverse
function* traverse(o, path=[]) {
for (var i in o) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath,o];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i], itemPath);
}
}
}
// Traverse usage:
//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse({
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
})) {
// do something here with each key and value
console.log(key, value, path, parent);
}
If you want only own enumerable properties (basically non-prototype chain properties) you can change it to iterate using Object.keys and a for...of loop instead:
function* traverse(o,path=[]) {
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath,o];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i],itemPath);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse({
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
})) {
// do something here with each key and value
console.log(key, value, path, parent);
}
EDIT: This edited answer solves infinite looping traversals.
Stopping Pesky Infinite Object Traversals
This edited answer still provides one of the added benefits of my original answer which allows you to use the provided generator function in order to use a cleaner and simple iterable interface (think using for of loops as in for(var a of b) where b is an iterable and a is an element of the iterable). By using the generator function along with being a simpler api it also helps with code reuse by making it so you don't have to repeat the iteration logic everywhere you want to iterate deeply on an object's properties and it also makes it possible to break out of the loop if you would like to stop iteration earlier.
One thing that I notice that has not been addressed and that isn't in my original answer is that you should be careful traversing arbitrary (i.e. any "random" set of) objects, because JavaScript objects can be self referencing. This creates the opportunity to have infinite looping traversals. Unmodified JSON data however cannot be self referencing, so if you are using this particular subset of JS objects you don't have to worry about infinite looping traversals and you can refer to my original answer or other answers. Here is an example of a non-ending traversal (note it is not a runnable piece of code, because otherwise it would crash your browser tab).
Also in the generator object in my edited example I opted to use Object.keys instead of for in which iterates only non-prototype keys on the object. You can swap this out yourself if you want the prototype keys included. See my original answer section below for both implementations with Object.keys and for in.
Worse - This will infinite loop on self-referential objects:
function* traverse(o, path=[]) {
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath, o];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i], itemPath);
}
}
}
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
// this self-referential property assignment is the only real logical difference
// from the above original example which ends up making this naive traversal
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path, parent);
}
To save yourself from this you can add a set within a closure, so that when the function is first called it starts to build a memory of the objects it has seen and does not continue iteration once it comes across an already seen object. The below code snippet does that and thus handles infinite looping cases.
Better - This will not infinite loop on self-referential objects:
function* traverse(o) {
const memory = new Set();
function * innerTraversal (o, path=[]) {
if(memory.has(o)) {
// we've seen this object before don't iterate it
return;
}
// add the new object to our memory.
memory.add(o);
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath, o];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* innerTraversal(o[i], itemPath);
}
}
}
yield* innerTraversal(o);
}
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
/// this self-referential property assignment is the only real logical difference
// from the above original example which makes more naive traversals
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
console.log(o);
//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path, parent);
}
EDIT: All above examples in this answer have been edited to include a new path variable yielded from the iterator as per #supersan's request. The path variable is an array of strings where each string in the array represents each key that was accessed to get to the resulting iterated value from the original source object. The path variable can be fed into lodash's get function/method. Or you could write your own version of lodash's get which handles only arrays like so:
function get (object, path) {
return path.reduce((obj, pathItem) => obj ? obj[pathItem] : undefined, object);
}
const example = {a: [1,2,3], b: 4, c: { d: ["foo"] }};
// these paths exist on the object
console.log(get(example, ["a", "0"]));
console.log(get(example, ["c", "d", "0"]));
console.log(get(example, ["b"]));
// these paths do not exist on the object
console.log(get(example, ["e", "f", "g"]));
console.log(get(example, ["b", "f", "g"]));
You could also make a set function like so:
function set (object, path, value) {
const obj = path.slice(0,-1).reduce((obj, pathItem) => obj ? obj[pathItem] : undefined, object)
if(obj && obj[path[path.length - 1]]) {
obj[path[path.length - 1]] = value;
}
return object;
}
const example = {a: [1,2,3], b: 4, c: { d: ["foo"] }};
// these paths exist on the object
console.log(set(example, ["a", "0"], 2));
console.log(set(example, ["c", "d", "0"], "qux"));
console.log(set(example, ["b"], 12));
// these paths do not exist on the object
console.log(set(example, ["e", "f", "g"], false));
console.log(set(example, ["b", "f", "g"], null));
EDIT Sep. 2020: I added a parent for quicker access of the previous object. This could allow you to more quickly build a reverse traverser. Also you could always modify the traversal algorithm to do breadth first search instead of depth first which is actually probably more predictable in fact here's a TypeScript version with Breadth First Search. Since this is a JavaScript question I'll put the JS version here:
var TraverseFilter;
(function (TraverseFilter) {
/** prevents the children from being iterated. */
TraverseFilter["reject"] = "reject";
})(TraverseFilter || (TraverseFilter = {}));
function* traverse(o) {
const memory = new Set();
function* innerTraversal(root) {
const queue = [];
queue.push([root, []]);
while (queue.length > 0) {
const [o, path] = queue.shift();
if (memory.has(o)) {
// we've seen this object before don't iterate it
continue;
}
// add the new object to our memory.
memory.add(o);
for (var i of Object.keys(o)) {
const item = o[i];
const itemPath = path.concat([i]);
const filter = yield [i, item, itemPath, o];
if (filter === TraverseFilter.reject)
continue;
if (item !== null && typeof item === "object") {
//going one step down in the object tree!!
queue.push([item, itemPath]);
}
}
}
}
yield* innerTraversal(o);
}
//your object
var o = {
foo: "bar",
arr: [1, 2, 3],
subo: {
foo2: "bar2"
}
};
/// this self-referential property assignment is the only real logical difference
// from the above original example which makes more naive traversals
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
//that's all... no magic, no bloated framework
for (const [key, value, path, parent] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path, parent);
}
Depends on what you want to do. Here's an example of traversing a JavaScript object tree, printing keys and values as it goes:
function js_traverse(o) {
var type = typeof o
if (type == "object") {
for (var key in o) {
print("key: ", key)
js_traverse(o[key])
}
} else {
print(o)
}
}
js> foobar = {foo: "bar", baz: "quux", zot: [1, 2, 3, {some: "hash"}]}
[object Object]
js> js_traverse(foobar)
key: foo
bar
key: baz
quux
key: zot
key: 0
1
key: 1
2
key: 2
3
key: 3
key: some
hash
If you're traversing an actual JSON string then you can use a reviver function.
function traverse (json, callback) {
JSON.parse(json, function (key, value) {
if (key !== '') {
callback.call(this, key, value)
}
return value
})
}
traverse('{"a":{"b":{"c":{"d":1}},"e":{"f":2}}}', function (key, value) {
console.log(arguments)
})
When traversing an object:
function traverse (obj, callback, trail) {
trail = trail || []
Object.keys(obj).forEach(function (key) {
var value = obj[key]
if (Object.getPrototypeOf(value) === Object.prototype) {
traverse(value, callback, trail.concat(key))
} else {
callback.call(obj, key, value, trail)
}
})
}
traverse({a: {b: {c: {d: 1}}, e: {f: 2}}}, function (key, value, trail) {
console.log(arguments)
})
I wanted to use the perfect solution of #TheHippo in an anonymous function, without use of process and trigger functions. The following worked for me, sharing for novice programmers like myself.
(function traverse(o) {
for (var i in o) {
console.log('key : ' + i + ', value: ' + o[i]);
if (o[i] !== null && typeof(o[i])=="object") {
//going on step down in the object tree!!
traverse(o[i]);
}
}
})
(json);
Most Javascript engines do not optimize tail recursion (this might not be an issue if your JSON isn't deeply nested), but I usually err on the side of caution and do iteration instead, e.g.
function traverse(o, fn) {
const stack = [o]
while (stack.length) {
const obj = stack.shift()
Object.keys(obj).forEach((key) => {
fn(key, obj[key], obj)
if (obj[key] instanceof Object) {
stack.unshift(obj[key])
return
}
})
}
}
const o = {
name: 'Max',
legal: false,
other: {
name: 'Maxwell',
nested: {
legal: true
}
}
}
const fx = (key, value, obj) => console.log(key, value)
traverse(o, fx)
My Script:
op_needed = [];
callback_func = function(val) {
var i, j, len;
results = [];
for (j = 0, len = val.length; j < len; j++) {
i = val[j];
if (i['children'].length !== 0) {
call_func(i['children']);
} else {
op_needed.push(i['rel_path']);
}
}
return op_needed;
};
Input JSON:
[
{
"id": null,
"name": "output",
"asset_type_assoc": [],
"rel_path": "output",
"children": [
{
"id": null,
"name": "output",
"asset_type_assoc": [],
"rel_path": "output/f1",
"children": [
{
"id": null,
"name": "v#",
"asset_type_assoc": [],
"rel_path": "output/f1/ver",
"children": []
}
]
}
]
}
]
Function Call:
callback_func(inp_json);
Output as per my Need:
["output/f1/ver"]
var test = {
depth00: {
depth10: 'string'
, depth11: 11
, depth12: {
depth20:'string'
, depth21:21
}
, depth13: [
{
depth22:'2201'
, depth23:'2301'
}
, {
depth22:'2202'
, depth23:'2302'
}
]
}
,depth01: {
depth10: 'string'
, depth11: 11
, depth12: {
depth20:'string'
, depth21:21
}
, depth13: [
{
depth22:'2201'
, depth23:'2301'
}
, {
depth22:'2202'
, depth23:'2302'
}
]
}
, depth02: 'string'
, dpeth03: 3
};
function traverse(result, obj, preKey) {
if(!obj) return [];
if (typeof obj == 'object') {
for(var key in obj) {
traverse(result, obj[key], (preKey || '') + (preKey ? '[' + key + ']' : key))
}
} else {
result.push({
key: (preKey || '')
, val: obj
});
}
return result;
}
document.getElementById('textarea').value = JSON.stringify(traverse([], test), null, 2);
<textarea style="width:100%;height:600px;" id="textarea"></textarea>
I've created library to traverse and edit deep nested JS objects. Check out API here: https://github.com/dominik791
You can also play with the library interactively using demo app:
https://dominik791.github.io/obj-traverse-demo/
Examples of usage:
You should always have root object which is the first parameter of each method:
var rootObj = {
name: 'rootObject',
children: [
{
'name': 'child1',
children: [ ... ]
},
{
'name': 'child2',
children: [ ... ]
}
]
};
The second parameter is always the name of property that holds nested objects. In above case it would be 'children'.
The third parameter is an object that you use to find object/objects that you want to find/modify/delete. For example if you're looking for object with id equal to 1, then you will pass { id: 1} as the third parameter.
And you can:
findFirst(rootObj, 'children', { id: 1 }) to find first object
with id === 1
findAll(rootObj, 'children', { id: 1 }) to find all objects
with id === 1
findAndDeleteFirst(rootObj, 'children', { id: 1 }) to delete first matching object
findAndDeleteAll(rootObj, 'children', { id: 1 }) to delete all matching objects
replacementObj is used as the last parameter in two last methods:
findAndModifyFirst(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) to change first found object with id === 1 to the { id: 2, name: 'newObj'}
findAndModifyAll(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) to change all objects with id === 1 to the { id: 2, name: 'newObj'}
We use object-scan for many data processing tasks. It's powerful once you wrap your head around it. Here is how you could do basic traversal
// const objectScan = require('object-scan');
const obj = { foo: 'bar', arr: [1, 2, 3], subo: { foo2: 'bar2' } };
objectScan(['**'], {
reverse: false,
filterFn: ({ key, value }) => {
console.log(key, value);
}
})(obj);
// => [ 'foo' ] bar
// => [ 'arr', 0 ] 1
// => [ 'arr', 1 ] 2
// => [ 'arr', 2 ] 3
// => [ 'arr' ] [ 1, 2, 3 ]
// => [ 'subo', 'foo2' ] bar2
// => [ 'subo' ] { foo2: 'bar2' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
This Will read All Nodes to a map.
function readJsonFile() {
let jsonString = getValueById("testDataContent");
let jsonObj = JSON.parse(jsonString);
let jsonElements = [];
jsonElements = traverse(jsonObj, jsonElements);
console.log(jsonElements)
}
function traverse(jsonObj, jsonElements) {
if (jsonObj !== null && typeof jsonObj == "object") {
Object.entries(jsonObj).forEach(([key, value]) => {
if (typeof value == "object") {
var obj = [];
let map = new Map();
map.set(key, traverse(value, obj))
jsonElements.push(map);
} else {
var obj = [];
obj.key = key;
obj.value = value;
jsonElements.push(obj);
}
});
} else {
}
return jsonElements;
}
You can get all keys / values and preserve the hierarchy with this
// get keys of an object or array
function getkeys(z){
var out=[];
for(var i in z){out.push(i)};
return out;
}
// print all inside an object
function allInternalObjs(data, name) {
name = name || 'data';
return getkeys(data).reduce(function(olist, k){
var v = data[k];
if(typeof v === 'object') { olist.push.apply(olist, allInternalObjs(v, name + '.' + k)); }
else { olist.push(name + '.' + k + ' = ' + v); }
return olist;
}, []);
}
// run with this
allInternalObjs({'a':[{'b':'c'},{'d':{'e':5}}],'f':{'g':'h'}}, 'ob')
This is a modification on (https://stackoverflow.com/a/25063574/1484447)
var localdata = [{''}]// Your json array
for (var j = 0; j < localdata.length; j++)
{$(localdata).each(function(index,item)
{
$('#tbl').append('<tr><td>' + item.FirstName +'</td></tr>);
}
The best solution for me was the following:
simple and without using any framework
var doSomethingForAll = function (arg) {
if (arg != undefined && arg.length > 0) {
arg.map(function (item) {
// do something for item
doSomethingForAll (item.subitem)
});
}
}

Categories