How can I reach inside nested object in javascript? - javascript

How do I reach isBoatOwner so I can return it's value in a array?
My code is returning undefined.
pluck(
[
{ name: "Tim", isBoatOwner: true },
{ name: "Matt", isBoatOwner: false },
{ name: "Elie" }
],
"isBoatOwner"
);
function pluck(defObj, key) {
let arr = [];
for (let i = 0; i < defObj.length; i++) {
if (Object.keys(defObj[i]) == key) {
arr.push(defObj[i][key]);
} else {
arr.push(undefined);
}
}
return arr.flat();
}

All you need is a simple .map():
console.log(pluck(
[
{ name: "Tim", isBoatOwner: true },
{ name: "Matt", isBoatOwner: false },
{ name: "Elie" }
],
"isBoatOwner"
));
function pluck(defObj, key) {
return defObj.map(function (obj) {
return obj[key];
});
}
So the above function collects all the values of isBoatOwner from the array and sends it as an array of values.
[
true,
false,
undefined
]

In your code you are trying to compare an array to a string to see if the property exists. That is never going to match
function pluck(defObj, key) {
let arr = [];
for (let i = 0; i < defObj.length; i++) {
// if (Object.keys(defObj[i]) == key) {
if (defObj[i][key] !== undefined) {
arr.push(defObj[i][key]);
} else {
arr.push(undefined);
}
}
return arr.flat();
}
var result = pluck(
[{
name: "Tim",
isBoatOwner: true
},
{
name: "Matt",
isBoatOwner: false
},
{
name: "Elie"
}
],
"isBoatOwner"
);
console.log(result);
But the check does not make too much sense since you are pushing undefined into it. So it could just be
function pluck(defObj, key) {
let arr = [];
for (let i = 0; i < defObj.length; i++) {
arr.push(defObj[i][key]);
}
return arr.flat();
}
var result = pluck(
[{
name: "Tim",
isBoatOwner: true
},
{
name: "Matt",
isBoatOwner: false
},
{
name: "Elie"
}
],
"isBoatOwner"
);
console.log(result);
Modern approach is just map
function pluck(defObj, key) {
// return defObj.map(function(item) { return item[key]; });
return defObj.map(item => item[key]);
}
var result = pluck(
[{
name: "Tim",
isBoatOwner: true
},
{
name: "Matt",
isBoatOwner: false
},
{
name: "Elie"
}
],
"isBoatOwner"
);
console.log(result);

Related

how to find object using recursion in javascript?

let tree = {
name: "A",
children: [
{
name: 'A-1',
children: [
{name: "A-1-A"},
{name: "A-1-B"},
]
},
{
name: 'B-1',
children: [
{
name: "B-1-A",
children: [
{name: "B-11-A"},
{name: "B-11-B"}
]
},
{name: "B-1-B"},
]
},
]
};
I am trying to find object from tree object using recursion .
when I call like this searchFn(tree,'A-1') it should return {
name: 'A-1',
children: [
{name: "A-1-A"},
{name: "A-1-B"},
]
} object
it I call like this searchFn(tree,'A-1-A') it should return this
{name: "A-1-A"}
I tried like this but not working
function searchFn(obj ,searchText){
if(obj.name === searchText) return obj
if(obj.children.length > 0){
return searchFn(obj.children.pop(),searchText)
}
return null
}
You need to iterate the children of the object and take a variable for the result.
function searchFn(object, searchText) {
var result;
if (object.name === searchText) return object;
(object.children || []).some(o => result = searchFn(o, searchText));
return result || null;
}
let tree = { name: "A", children: [{ name: 'A-1', children: [{ name: "A-1-A" }, { name: "A-1-B" }] }, { name: 'B-1', children: [{ name: "B-1-A", children: [{ name: "B-11-A" }, { name: "B-11-B" }] }, { name: "B-1-B" }] }] };
console.log(searchFn(tree, 'foo'));
console.log(searchFn(tree, 'A-1'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
First, you should create a class for readability. Then you should have a loop inside the function that iterates over the children and only returns if a child is found.
class Node {
static fromStruct = (struct) => {
const tree = new Node(struct.name);
if(!struct.children) return tree;
for(const child of struct.children) {
tree.children.push(Node.fromStruct(child));
}
return tree;
}
constructor(name){
this.name = name;
this.children = [];
}
addChild = (parentName, childName) => {
const parent = this.searchFn(parentName);
if(!parent) throw new Error("Parent not found");
parent.children.push(new Node(childName));
}
searchFn = (name) => {
if(this.name === name) return this;
for(const child of this.children) {
const found = child.searchFn(name);
if(found !== null) return found;
}
return null;
}
}
const data = {
name: "A",
children: [
{
name: 'A-1',
children: [
{name: "A-1-A"},
{name: "A-1-B"},
]
},
{
name: 'B-1',
children: [
{
name: "B-1-A",
children: [
{name: "B-11-A"},
{name: "B-11-B"}
]
},
{name: "B-1-B"},
]
},
]
};
const tree = Node.fromStruct(data);
console.log(tree.searchFn("A-1-A"));
const tree = {"name":"A","children":[{"name":"A-1","children":[{"name":"A-1-A"},{"name":"A-1-B"}]},{"name":"B-1","children":[{"name":"B-1-A","children":[{"name":"B-11-A"},{"name":"B-11-B"}]},{"name":"B-1-B"}]}]}
const searchFn = (tree, name) => {
let result = null;
if (typeof tree !== "object") return result;
if (tree.name === name) return tree;
if (tree.children && tree.children.length) {
tree.children.some(data => (result = searchFn(data, name)));
}
return result;
};
console.log(searchFn(tree, "A-1-A"));
console.log(searchFn(tree, "A-1"));
console.log(searchFn(tree, ""));
.as-console-row {color: blue!important}
You can try something like this
let tree = { name: "A", children: [{ name: 'A-1', children: [{ name: "A-1-A" }, { name: "A-1-B" }] }, { name: 'B-1', children: [{ name: "B-1-A", children: [{ name: "B-11-A" }, { name: "B-11-B" }] }, { name: "B-1-B" }] }] };
function searchFn(obj, text){
if(obj.name === text) return obj
else{
if(obj && obj.children && Array.isArray(obj.children)){
for(let value of obj.children){
if(searchFn(value, text)){
return searchFn(value, text)
}
}
}
}
return null
}
console.log(searchFn(tree, 'A-1'))
console.log(searchFn(tree, 'A-1-A'))
console.log(searchFn(tree, 'A-A-A'))
The problem with your function is that it only checks for the popped element from the array in the children property of the passed object, and not the other elements. Try this:
function searchFn(obj ,searchText) {
if(obj.name === searchText) return obj;
if(obj.children) {
for (let x of obj.children) {
let y = searchFn(x,searchText);
if (y)
return y;
}
}
return null;
}

Get all parents of an element in nested object

I have the following data stored in a variable:
let categories = [
{
name: "a",
nodes: [
{
name: "aa",
nodes: [
{
name: "aaa"
}
]
},
{
name: "ab",
},
{
name: "ac",
},
{
name: "ad",
}
]
},
{
name: "b",
nodes: [
{
name: "ba",
},
{
name: "bb",
},
{
name: "bc",
},
{
name: "bd",
}
]
}
];
And I have the following recursive function which accepts the categories variable and name.
function getCategoryParents(categories, name) {
for (let index = 0; index < categories.length; index++) {
const category = categories[index];
if (category.name === name) {
}
if (category.nodes && category.nodes.length) {
category.nodes.forEach(cat => this.getCategoryParents([cat], name));
}
}
}
I want to return an array of names containing the name in the parameter and the parents of that name.
For example if I called getCategoryParents(categories, "aaa") it should returns ["a", "aa", "aaa"]. because aa is the parent of aaa and a is the parent of aa.
I hope it's clear.
I tweaked your function so it would actually return some values when it finds the matches :
function getCategoryParents(arr, name) {
for (let child of arr) {
if (child.name === name) {
return name;
} else if (child.nodes.length > 0) {
var x = getCategoryParents(child.nodes, name);
if (x) return Array.isArray(x) ? [child.name, ...x] : [child.name, x];
}
}
}
let categories = [
{
name: "a",
nodes: [
{
name: "aa",
nodes: [
{
name: "aaa"
}
]
},
{
name: "ab"
},
{
name: "ac"
},
{
name: "ad"
}
]
},
{
name: "b",
nodes: [
{
name: "ba"
},
{
name: "bb"
},
{
name: "bc"
},
{
name: "bd"
}
]
}
];
const result = getCategoryParents(categories, "aaa");
console.log(result); // ["a", "aa", "aaa"]

compare array of objects and remove specific item

arr1 = [
{
name: "will",
value: "1"
},
{
name: "nelson",
value: "3"
}
];
and
arr2 = [
{
name: "will",
value: 1,
submenu: [
{
name: "ralph",
value: 2
}
]
}
]
then remove ralph from the second array. i already created a function who do it but just check the first element and not verify the submenu.
comparador(arrSecundario) {
return (arrAtual) => {
return arrSecundario.filter(function (other) {
return other.value === arrAtual.value;
}).length !== 0;
};
}
this.arr2.filter(this.comparador(this.arr1));
Need to map array after filter. You can do like this and can also add "prop === 'submenu'" for specifically checking submenu inner array only.
var arr1 = [
{
name: "will",
value: "1"
},
{
name: "nelson",
value: "3"
}
];
var arr2 = [
{
name: "will",
value: 1,
submenu: [
{
name: "ralph",
value: 2
},
// {
// name: "nelson",
// value: 3
// }
]
}
];
function filterComparador(arrSecundario) {
return (arrAtual) => {
return arrSecundario.filter((other) => {
return other.value == arrAtual.value;
}).length != 0;
};
}
function mapComparador(arrSecundario) {
return (arrAtual) => {
Object.keys(arrAtual).forEach((prop) => {
if (Array.isArray(arrAtual[prop])) {
let propValue = arrAtual[prop].filter(this.filterComparador(arrSecundario));
if (propValue.length > 0) {
arrAtual[prop] = propValue.map(this.mapComparador(this.arrSecundario));
} else {
delete arrAtual[prop];
}
}
});
return arrAtual;
};
}
var manipulatedArray = this.arr2.filter(this.filterComparador(this.arr1))
.map(this.mapComparador(this.arr1));
console.log(manipulatedArray);

Need help recursively iterating through all levels of a Javascript object

I am trying to create an object, and within this object will be the name and an array of other objects under children. Really I want to create a hierarchy from another object.
I have tried to create a recursive function but what I end up with is a vertical slice rather than the whole picture. I am unsure how to adjust my recursion to go back add iterate through the other horizontal objects.
buildHierarchy(json) {
console.log("Entered Build Hierarchy");
let newObject;
newObject = this.buildChildren(json);
console.log(newObject);
return newObject
}
buildChildren(json) {
let returnObject;
for (var key in json) {
returnObject = {
name: key,
children: []
};
var subObject = json[key];
if (Array.isArray(subObject)) {
returnObject = {
name: key,
_proficiency: subObject
}
} else {
returnObject["children"].push(this.buildChildren(subObject))
}
}
return returnObject;
}
Imagine you have this json file below
{users:
{sandy: {
posts: [
{ title: 'Bar', comments: [ 'Ok' ] },
]
followers: [
{ name: 'Foo' },
]
}
ron: {
photos: [
{ title: 'Foo', comments: [ 'Ok' ] },
]
}
}
}
I am looking for something like this...
{
name: "users",
children: [
{
name: "sandy",
children: [
{
name: "posts",
children: [
{
name: "Bar",
comments: "OK"
}],
{ name: "followers"
children: [
{
name: "Foo"
}
]
}
}
]
},
{
name: "ron",
photos: [
{
name: "photos",
children: [
{
name: "Foo",
comments: "OK"
}
]
}
]
}
]
}
From what I see as the output I'm making these inferences:
If the child object is an array, it is blindly copied to children key
If the child element is an object, then they are changed to {name: <KEY>, children: <VALUE>}
function buildChildren(json) {
let returnObject = [];
if (typeof json !== 'object') {
return json;
}
for (var key in json) {
if (Array.isArray(json)) {
returnObject.push(buildChildren(json[key]));
} else {
returnObject.push({
name: key,
children: buildChildren(json[key])
});
}
}
return returnObject;
}
function buildHierarchy(json) {
console.log("Entered Build Hierarchy");
let newObject;
newObject = buildChildren(json);
console.log(newObject);
}
function buildChildren(json) {
if (Array.isArray(json)) {
return {
_proficiency: json
}
}
var children = Object.keys(json);
let final = [];
for (var i = 0; count = children.length, i < count; i++) {
let result = {
name: children[i]
}
let d = buildChildren(json[children[i]]);
if (d._proficiency) {
result._proficiency = d._proficiency;
} else {
result.children = d;
}
final.push(result);
}
return final;
}

How to recursively process a JSON data and return the processed JSON from a function?

I have below JSON data with nested objects. I want to delete the 'id' from this structure and return the changed JSON from the function. I have tried to do it recursively below way but not able to return the changed JSON.
var jsonStr =
{"_id":"7r0c0342e",
"user":"myuser",
"project":"abcd",
"info":{"DOMAIN":{"Department":{"profile":[{"workex":8,"name":"alex","id":82838},
{"workex":8,"name":"smith","id":84838} ]}}} };
processJSON(jsonStr);
function processJSON(jsondata) {
for (var i in jsondata) {
var row = jsondata[i];
if(typeof row == "object") {
processJSON(row);
} else if(typeof row == 'number') {
if(i == 'id') {
delete jsondata[i];
} else {
continue;
}
} else {
continue;
}
}
}
console.log(jsonStr);
How can I return the rest of the JSON from the processJSON() and hold that in a variable ? Secondly, is this the correct way to do it recursively ?
Thanks.
With your approach, you mutate the original object, so in a way, you don't have to return anything.
If you want to keep the original object and return a changed copy instead, you will first need to make a copy of the object, and run your algorithm on that. You can make a shallow copy of an object e.g. using Object.assign:
var jsonStr = {"_id":"7r0c0342e", "user":"myuser", "project":"data_mining", "info":{"DOMAIN":{"Department":{"profile":[{"workex":8,"name":"alex","id":82838}, {"workex":8,"name":"smith","id":84838} ]}}} };
console.log(processJSON(jsonStr));
function processJSON(jsondata) {
var output = Object.assign({}, jsondata)
for (var i in output) {
var row = output[i];
if (typeof row == "object") {
output[i] = processJSON(row);
} else if (typeof row == 'number') {
if (i == 'id') {
delete output[i];
} else {
continue;
}
} else {
continue;
}
}
return output;
}
var jsonStr =
{
"_id": "7r0c0342e",
"user": "myuser",
"project": "data_mining",
"info": {
"DOMAIN": {
"Department": {
"profile": [{"workex": 8, "name": "alex", "id": 82838},
{"workex": 8, "name": "smith", "id": 84838}]
}
}
}
};
let modifedJson = JSON.parse(JSON.stringify(jsonStr));
parseJson = function (json) {
for (let key in json) {
if (key === 'id') {
delete json[key];
}
else if (typeof json[key] === 'object') {
parseJson(json[key])
}
}
}
parseJson(modifedJson)
console.log('modified',modifedJson)
console.log('original',jsonStr)
Here is a solution using object-scan that modifies the data in place...
// const objectScan = require('object-scan');
const jsonStr = { _id: '7r0c0342e', user: 'myuser', project: 'abcd', info: { DOMAIN: { Department: { profile: [{ workex: 8, name: 'alex', id: 82838 }, { workex: 8, name: 'smith', id: 84838 }] } } } };
const prune = (obj) => objectScan(['**.id'], {
rtn: 'count',
filterFn: ({ parent, property }) => {
delete parent[property];
return true;
}
})(obj);
console.log(prune(jsonStr)); // returns amount of deletes
// => 2
console.log(jsonStr);
// => { _id: '7r0c0342e', user: 'myuser', project: 'abcd', info: { DOMAIN: { Department: { profile: [ { workex: 8, name: 'alex' }, { workex: 8, name: 'smith' } ] } } } }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan
...and a different solution that clones the input and omits the ids in the clone process...
// const objectScan = require('object-scan');
const jsonStr = { _id: '7r0c0342e', user: 'myuser', project: 'abcd', info: { DOMAIN: { Department: { profile: [{ workex: 8, name: 'alex', id: 82838 }, { workex: 8, name: 'smith', id: 84838 }] } } } };
const clone = (obj) => objectScan(['**', '!**.id'], {
breakFn: ({ isMatch, property, value, isLeaf, context }) => {
if (!isMatch) {
return;
}
const ref = context[context.length - 1];
if (!(property in ref)) {
if (isLeaf) {
ref[property] = value;
} else {
ref[property] = Array.isArray(value) ? [] : {};
}
}
context.push(ref[property]);
},
filterFn: ({ context }) => {
context.pop();
}
})(obj, [{}])[0];
const r = clone(jsonStr);
console.log(jsonStr);
// => { _id: '7r0c0342e', user: 'myuser', project: 'abcd', info: { DOMAIN: { Department: { profile: [ { workex: 8, name: 'alex', id: 82838 }, { workex: 8, name: 'smith', id: 84838 } ] } } } }
console.log(r);
// => { info: { DOMAIN: { Department: { profile: [ { name: 'alex', workex: 8 }, { name: 'smith', workex: 8 } ] } } }, project: 'abcd', user: 'myuser', _id: '7r0c0342e' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan

Categories