I have been asked this question in an interview. How to solve this? The object and consoles statements are mentioned. I am not getting how to implement the function findPath?
class Obj {
constructor() {
this.data = {
a: {
b: {
c: 12
}
}
};
}
findPath = (str) => {
let sol = this.data;
for (let key of str.split(".")) {
sol = sol[key];
if (!sol) {
return undefined;
}
}
return JSON.stringify(sol);
};
}
let obj = new Obj();
console.log(obj.findPath("a.b.c"));
console.log(obj.findPath("a.b"));
console.log(obj.findPath("a.b.d"));
console.log(obj.findPath("a.c"));
console.log(obj.findPath("a.b.c.d"));
console.log(obj.findPath("a.b.c.d.e"));
var obj = {
a: {
b: {
c: 1
}
}
}
obj.findPath = function(path) {
const keys = path.split('.');
return keys.reduce((currentPath, key) => {
return currentPath && currentPath[key]
}, this)
}
console.log(obj.findPath('a'))
console.log(obj.findPath('a.b'))
console.log(obj.findPath('a.b.c'))
console.log(obj.findPath('a.b.c.d'))
This could do it
var obj = {
a: {
b: {
c: 1
}
}
}
function findPath(path) {
const paths = path.split('.');
let innerObj = {...obj};
for (let i = 0; i < paths.length; i++) {
innerObj = innerObj && innerObj[paths[i]] || null;
}
return innerObj;
}
console.log(findPath("a.b.c"));
console.log(findPath("a.b"));
console.log(findPath("a.b.d"));
console.log(findPath("a.c"));
console.log(findPath("a.b.c.d"));
console.log(findPath("a.b.c.d.e"));
A simple approach
const obj = {
a: {
b: {
c: 12,
},
},
k: null,
};
const testFunc = (obj, k) => {
const arr = k.split(".");
for (let i = 0; i < arr.length; i++) {
obj = obj[arr[i]];
}
return obj;
};
console.log(testFunc(obj, "k")); //null
console.log(testFunc(obj, "a.b.c")); //12
console.log(testFunc(obj, "a.b.c.d")); //undefined
console.log(testFunc(obj, "f")); //undefined
Related
how could I avoid a duplicate in array, I'm looping the array I receive, and I need to save in mongodb, so it's duplicating the array's indexes, maybe using a filter I thought, wouldn't it be harmful to the system maybe?, and how could in this case use a filter to filter duplicates in an array with a structure that has objects, strings, etcs
const hasDate = await Universities.find({country})
if(hasDate.length > 0) {
return new Error('Dados já existe');
} else {
for(let i in returnApi) {
await Universities.create({
domains: returnApi[i].domains,
alpha_two_code: returnApi[i].alpha_two_code,
country: returnApi[i].country,
web_pages: returnApi[i].web_pages,
name: returnApi[i].name,
state_province: returnApi[i].stateprovince
})
};
await insertNameUniversities(returnApi)
};
};
Ok so basically we can use some deep compare method we found online.
const person1 = {
"firstName": "John",
"lastName": "Doe",
"age": 35
};
const person2 = {
"firstName": "John",
"lastName": "Doe",
"age": 35,
};
const isDeepEqual = (object1, object2) => {
const objKeys1 = Object.keys(object1);
const objKeys2 = Object.keys(object2);
if (objKeys1.length !== objKeys2.length) return false;
for (var key of objKeys1) {
const value1 = object1[key];
const value2 = object2[key];
const isObjects = isObject(value1) && isObject(value2);
if ((isObjects && !isDeepEqual(value1, value2)) ||
(!isObjects && value1 !== value2)
) {
return false;
}
}
return true;
};
const isObject = (object) => {
return object != null && typeof object === "object";
};
console.log(isDeepEqual(person1, person2)); //true
As for the duplicates removal, let's do it manually, just 2 nested loops
const person1 = {
"firstName": "John",
"lastName": "Doe",
"age": 35
};
const person2 = {
"firstName": "Frank",
"lastName": "Fabian",
"age": 72,
};
var arr = [person1, person2, { ...person1 }]
// console.log(arr)
const isDeepEqual = (object1, object2) => {
const isObject = (object) => {
return object != null && typeof object === "object";
};
const objKeys1 = Object.keys(object1);
const objKeys2 = Object.keys(object2);
if (objKeys1.length !== objKeys2.length) return false;
for (var key of objKeys1) {
const value1 = object1[key];
const value2 = object2[key];
const isObjects = isObject(value1) && isObject(value2);
if ((isObjects && !isDeepEqual(value1, value2)) ||
(!isObjects && value1 !== value2)
) {
return false;
}
}
return true;
};
function removeDuplicates(arr) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (isDeepEqual(arr[i], arr[j])) {
arr[j] = 'delete-me-later'
}
}
}
return arr.filter(item => item !== 'delete-me-later');
}
console.log(removeDuplicates(arr))
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
I want to find the first array in an object in Javascript. However my functions cause an error:
el is undefined
el contains the object that looks like this:
data = {
foo: {
bar: [{object a},
{object b},
{object c}
]
}
}
let el = data;
el = this.searchArray(el);
el.forEach(element => {
console.log(element);
let siblingData = this.injectFilterParameters(element);
});
//here is unimportant code
searchArray(obj) {
if (Array.isArray(obj)) {
return obj;
} else {
Object.keys(obj).forEach(key => {
if (Array.isArray(obj[key])) {
return obj[key];
} else {
return this.searchArray(obj[key]);
}
})
}
}
const data = {
foo: {
bar: [
{ object: 'a' },
{ object: 'b' },
{ object: 'c' }
]
}
}
console.log(findArray(data))
function findArray(data: unknown): unknown[] | undefined {
if (Array.isArray(data)) {
return data
}
if (typeof data !== 'object') {
return undefined
}
const object = data as Record<string, unknown>
for (const key of Object.keys(object)) {
const value = object[key]
const valueSearchResult = findArray(value)
if (valueSearchResult != undefined) {
return valueSearchResult
}
}
return undefined
}
I'm trying to build an object given an array of objects
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
to look like this
{
x: {
a: {
z: 'Something for Z'
},
y: 'Something for Y'
}
}
I have this code
const buildObj = data => {
let obj = {}
data.forEach(item => {
let items = item.name.split('.')
items.reduce((acc, val, idx) => {
acc[val] = (idx === items.length - 1) ? item.value : {}
return acc[val]
}, obj)
})
return obj
}
buildObj(someArray)
but it doesn't include the y keypair. what's missing?
What you want to do is create an object, then for each dotted path, navigate through the object, creating new object properties as you go for missing parts, then assign the value to the inner-most property.
const someArray = [{"name":"x.y","value":"Something for Y"},{"name":"x.a.z","value":"Something for Z"}]
const t1 = performance.now()
const obj = someArray.reduce((o, { name, value }) => {
// create a path array
const path = name.split(".")
// extract the inner-most object property name
const prop = path.pop()
// find or create the inner-most object
const inner = path.reduce((i, segment) => {
// if the segment property doesn't exist or is not an object,
// create it
if (typeof i[segment] !== "object") {
i[segment] = {}
}
return i[segment]
}, o)
// assign the value
inner[prop] = value
return o
}, {})
const t2 = performance.now()
console.info(obj)
console.log(`Operation took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
This is ABD at this point but I did it with a recursive builder of the path.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
const createPath = (path, value) => {
if(path.length === 1){
let obj = {}
obj[path.shift()] = value
return obj
}
let key = path.shift();
let outObject = {}
outObject[key] = { ...createPath(path, value) }
return outObject
}
const createObjectBasedOnDotNotation = (arr) => {
let outObject = {}
for(let objKey in arr){
const { name, value } = arr[objKey];
let object = createPath(name.split("."), value)
let mainKey = Object.keys(object)[0];
!outObject[mainKey] ?
outObject[mainKey] = {...object[mainKey]} :
outObject[mainKey] = {
...outObject[mainKey],
...object[mainKey]
}
}
return outObject
}
console.log(createObjectBasedOnDotNotation(someArray))
Here's an option using for loops and checking nesting from the top down.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
function parseArr(arr) {
const output = {};
for (let i = 0; i < arr.length; i++) {
const {name, value} = arr[i];
const keys = name.split('.');
let parent = output;
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
if (!parent.hasOwnProperty(key)) {
parent[key] = j === keys.length - 1 ? value : {};
}
parent = parent[key];
}
}
return output;
}
console.log(parseArr(someArray));
I have a json object with objects inside of it
such as user: {"name": "tim"} and would like a way to turn that in "user.name": 'tim'
I've tried: Javascript Recursion normalize JSON data
Which does not return the result I want, also tried some packages, no luck
You can use a recursive approach to flatten nested objects, by concatenating their keys, as shown below:
const flattenObject = (obj) => {
const flatObject = {};
Object.keys(obj).forEach((key) => {
const value = obj[key];
if (typeof value === 'object') {
const flatNestedObject = flattenObject(value);
Object.keys(flatNestedObject).forEach((nestedKey) => {
flatObject[`${key}.${nestedKey}`] = flatNestedObject[nestedKey];
});
} else {
flatObject[key] = value;
}
});
return flatObject;
};
const obj = {
user: { name: 'tim' },
};
console.log(flattenObject(obj));
This solution works for any amount of levels.
If your environment does not support Object.keys, you can use for..in instead:
const flattenObject = (obj) => {
const flatObject = {};
for (const key in obj) {
if (!obj.hasOwnProperty(key)) continue;
const value = obj[key];
if (typeof value === 'object') {
const flatNestedObject = flattenObject(value);
for (const nestedKey in flatNestedObject) {
if (!flatNestedObject.hasOwnProperty(nestedKey)) continue;
flatObject[`${key}.${nestedKey}`] = flatNestedObject[nestedKey];
}
} else {
flatObject[key] = value;
}
}
return flatObject;
};
const obj = {
user: { name: 'tim' },
};
console.log(flattenObject(obj));
This can easily be done like so:
const myObject = {
user: {
firstname: "john",
lastname: "doe"
}
}
function normalize(suppliedObject = {}) {
const newObject = {};
for (const key of Object.keys(suppliedObject)) {
for (const subKey of Object.keys(suppliedObject[key])) {
newObject[`${key}.${subKey}`] = suppliedObject[key][subKey];
}
}
return newObject;
}
console.log(normalize(myObject));
Be aware that this only normalizes 1 level deep. You can extend the function to normalize all the way down to the last level.
Say I have an object like below:
let obj = {
mounted: (value) => {
return "Yeesss" + value;
},
a: "123123",
c: {
d: (key) => {
return key + 1;
}
}
}
I can stringify the object and its functions like so:
let objString = JSON.stringify(obj, (key, value) => {
if(typeof value === "function") return "[Function]" + value;
return value;
});
which will then be like:
{
"mounted":"[Function](value) => {\n return \"Yeesss\" + value;\n }",
"a":"123123",
"c":{
"d":"[Function](key) => {\n return key + 1;\n }"
}
}
I can save this string to a .json file and read it and parse it like below which will give me back the same object:
let obj = JSON.parse(objString, (key, value) => {
if(typeof value === "string" && value.startsWith("[Function]")){
value = value.substring(10);
value = eval(value);
return value;
}
return value;
});
What I want to know is how can I save that object in the beginning with fs in a .js file in the following format:
module.exports = {
mounted: (value) => {
return "Yeesss" + value;
},
a: "123123",
c: {
d: (key) => {
return key + 1;
}
}
}
So that I can require it and use it some other time in the future.
You could do something like this:
Use JSON.stringify() with the function-handling to produce a string.
Search and replace the function-values with an dequoted and unescaped value.
Add module prefix.
let obj = {
mounted: (value) => {
return "Yeesss" + value;
},
a: "123123",
c: {
d: (key) => {
return key + 1;
}
}
};
let json = JSON.stringify(obj, (key, value) => {
if (typeof value === 'function') {
return '[FUNCTION]' + value;
}
return value;
}, ' ');
let moduleJavascript = json.replace(/"(\[FUNCTION])?((?:\\.|[^\\"])*)"(:)?/g, (match, group1, group2, group3) => {
if (group1) return JSON.parse('"' + group2 + '"');
if (group3 && /^\w+$/.test(group2)) return group2 + ':';
return match;
});
moduleJavascript = 'module.exports = ' + moduleJavascript + ';';
console.log(moduleJavascript);
If this gets too complicated, you might consider using a code generation tool. EJS might fit your needs.
Template:
module.exports = {
mounted: (value) => {
return "Yeesss" + value;
},
a: <%= locals.avalue %>,
c: {
d: (key) => {
return key + 1;
}
}
};
And call with:
let ejs = require('ejs'),
fs = require('fs');
fs.readFile('template.ejs', (err, templateText) => {
if (err) throw err;
let moduleJavascript = ejs.render(templateText, {
// Arguments into the template
avalue: "123123"
}, {
// To make <%= %> escape JavaScript instead of HTML
escape: JSON.stringify
});
});