I would like to get a value from an object with accessing it with array of strings.
Static example: Input: ['a','b','c'] Output: function (t) { t.a.b.c; }
I would like to make a function that resolves the problem for any array.
function (state) {
let value = state;
for (let i = 0; i < propNames.length; i++) {
value = value[propNames[i]];
}
return value;
};
Other solution is a generator for a function by reducer.
These are working. I would like to know if there is any other faster solutions that I didn't think of.
You can test here the algorithms. There is a place where your code can be added.
A fast way to do it is to iterate over the properties and access the inner objects sequentially, you can do this using Array.reduce() or a for loop:
const get = (obj, props) => props.reduce((out, p) => out && out[p] || undefined, obj);
const obj = { a: { b: { c: 5 } } };
console.log(get(obj, ['a', 'b', 'c']));
console.log(get(obj, ['a', 'b', 'c', 'd', 'e']));
Or, you could evaluate the expression using eval(), however, this is probably the slowest way to do it, I do not recomment it:
const get = (obj, props) => {
try {
return eval(`obj.${props.join('.')}`);
} catch {
return undefined;
}
}
const obj = { a: { b: { c: 5 } } };
console.log(get(obj, ['a', 'b', 'c']));
console.log(get(obj, ['a', 'b', 'c', 'd', 'e']));
Related
I want to get a nested property name in an object during object construction.
What am I doing wrong? How do I get the expected output: 'c' from the nested object?
Starting point: MDN documentation
const obj = {
log: ['a', 'b', 'c'],
get latest() {
return this.log[this.log.length - 1];
}
};
console.log(obj.latest);
// Expected output: "c"
// Actual output: "c"
Confirmed. The above starting example works.
Now, I want to add nesting (obj.level1). This is where things fall apart.
Modification attempt 1: not working
const obj = {
level1: {
log: ['a', 'b', 'c'],
get latest() {
return this.log[this.log.length - 1];
}
}
};
console.log(obj.latest);
// Expected output: "c"
// Actual output: undefined
Modification attempt 2: not working
const obj = {
level1: {
log: ['a', 'b', 'c'],
get latest() {
return this.log[this.level1.log.length - 1];
}
}
};
console.log(obj.latest);
// Expected output: "c"
// Actual output: undefined
Your latest function exists on the level1 depth. So the following works:
console.log(obj.level1.latest)
However, if that's not your intention, you should write your object as such.
const obj = {
level1: {
log: ['a', 'b', 'c']
},
get latest() {
return this.level1.log.at(-1);
}
};
In your modifications obj doesn't have latest getter. It's in child object level1, so just try logging obj.level1.latest.
I have many values in string array. ['A','B','C','D','E'].
I have to search like this. if Array contains A ,B then it is admin. if it contains C,E then it is resercher. if it is containing B,C,D then it is manager.
I am writing below code for it. its not working. can you please help me on same.
const groups = ['A','B','C','D','E']
for (let i = 0; i < groups.length; i++) {
if (groups[i]==='A'&& groups[i] ==='B' ) setAdmin(true);
if (groups[i]==='C' && groups[i] ==='E' ) setResearcher(true);
if (groups[i]==='B' && groups[i] ==='C' && groups[i] ==='D' ) setRiskMgr(true);
}
I know it is not working because it is comparing element with multiple values. How can I resolve this?
You can use every and includes to utilize your logic
const groups = ['A', 'B', 'C', 'D', 'E']
const userGroups = {
admin: ['A', 'B'],
researcher: ['C', 'E'],
riskManager: ['B', 'C', 'D']
}
function setAdmin() {
console.log('admin')
}
function setResearcher() {
console.log('researcher')
}
function setRiskMgr() {
console.log('risk manager')
}
if (userGroups.admin.every(group => groups.includes(group))) setAdmin(true);
if (userGroups.researcher.every(group => groups.includes(group))) setResearcher(true);
if (userGroups.riskManager.every(group => groups.includes(group))) setRiskMgr(true);
Less repeated code with a separate object for role checks
const groups = ['A', 'B', 'C', 'D', 'E']
const userGroups = {
admin: {
values: ['A', 'B'],
set: function() {
setAdmin(true)
}
},
researcher: {
values: ['C', 'E'],
set: function() {
setResearcher(true)
}
},
riskManager: {
values: ['B', 'C', 'D'],
set: function() {
setRiskMgr(true);
}
}
}
function setAdmin() {
console.log('admin')
}
function setResearcher() {
console.log('researcher')
}
function setRiskMgr() {
console.log('risk manager')
}
for(const key in userGroups) {
if(userGroups[key].values.every(group => groups.includes(group))) {
userGroups[key].set();
}
}
As #ChrisG mentioned, you can use Array.includes or Array.some instead.
const groups = ['A','B','C','D','E']
if (groups.some(group => ['A', 'B'].includes(group))) {
setAdmin(true);
} else if (...) {
...
}
Its quite a simple solution with Array.includes
const groups = ['A','B','C','D','E']
if(groups.includes('A') && groups.includes('B')) {
setAdmin(true);
} else if(groups.includes('C') && groups.includes('E')) {
setReasercher(true)
} // ...
Assuming there is no issue with React useState, are you referring to OR, || statement, if so #Nick Vu has the answer, since you are just looping through the groups list, there is NO WAY to have two same element at single integration.
Else, if you want to achieve AND, && condition, then solution is otherwise.
const groups = ['A','B','C','D','E']
function setAdmin() {
console.log('admin')
}
function setResearcher() {
console.log('researcher')
}
function setRiskMgr() {
console.log('risk manager')
}
if(arr.some(a=>a==="A")&&arr.some(a=>a==="B")) setAdmin(true);
if(arr.some(a=>a==="C")&&arr.some(a=>a==="E")) setResearcher(true);
if(arr.some(a=>a==="B")&&arr.some(a=>a==="C")&&arr.some(a=>a==="D")) setRiskMgr(true);
Is there a way to generate a nested JavaScript Object from entries?
Object.fromEntries() doesn't quite do it since it doesn't do nested objects.
const entries = [['a.b', 'c'], ['a.d', 'e']]
// Object.fromEntries(entries) returns:
{
'a.b': 'c',
'a.d': 'e',
}
// whatIAmLookingFor(entries) returns:
{
a: {
b: 'c',
d: 'e',
}
}
You could reduce the array entries and reduce the keys as well. Then assign the value to the final object with the last key.
const
setValue = (object, [key, value]) => {
const
keys = key.split('.'),
last = keys.pop();
keys.reduce((o, k) => o[k] ??= {}, object)[last] = value;
return object;
},
entries = [['a.b', 'c'], ['a.d', 'e']],
result = entries.reduce(setValue, {});
console.log(result);
I think I found a way using lodash:
import set from 'lodash/set'
const result = {}
const entries = [['a.b', 'c'], ['a.d', 'e']]
entries.forEach((entry) => {
const key = entry[0]
const value = entry[1]
set(result, key, value)
})
I have a JavaScript object array with the following structure:
somedata = {
foo: {
bar: [
{
baz: [
{
someprop: 'a'
},
{
someprop: 'b'
},
{
someprop: 'c'
}
]
},
{
baz: [
{
someprop: 'd'
},
{
someprop: 'e'
},
{
someprop: 'f'
}
]
}
]
}
}
I want to extract someprop field from this JavaScript object as an array ['a', 'b', 'c', 'd', 'e', 'f']
currently, this is my code logic to extract someprop field as an array:
const result = []
somedata.foo.bar.forEach(x => {
x.baz.forEach(y => {
result.push(y.someprop)
})
})
console.log(result) // prints ["a", "b", "c", "d", "e", "f"]
i tried to make the code more reusable by creating a function:
function extractToArray(data, arr, prop) {
let result = []
data.forEach(x => {
x[arr].forEach(y => {
result.push(y[prop])
})
})
return result;
}
console.log(extractToArray(somedata.foo.bar, 'baz', 'someprop'))
But is there a more concise, elegant, cleaner way to achieve this?
Note: possible duplicate covers an array of objects, but this is regarding an array of objects of an array of objects (so a simple map solution won't work).
You can use flatMap for that:
const somedata = {foo:{bar:[{baz:[{someprop:"a"},{someprop:"b"},{someprop:"c"}]},{baz:[{someprop:"d"},{someprop:"e"},{someprop:"f"}]}]}};
const result = somedata.foo.bar.flatMap(({baz}) => baz.map(({someprop}) => someprop));
console.log(result);
Note that not every current browser supports this yet, so you might want to use a polyfill.
You could create recursive function that will find your prop on any level and return array as a result.
const somedata = {"foo":{"bar":[{"baz":[{"someprop":"a"},{"someprop":"b"},{"someprop":"c"}]},{"baz":[{"someprop":"d"},{"someprop":"e"},{"someprop":"f"}]}]}}
function get(data, prop) {
const result = [];
for (let i in data) {
if (i == prop) result.push(data[prop]);
if (typeof data[i] == 'object') result.push(...get(data[i], prop))
}
return result;
}
console.log(get(somedata, 'someprop'))
A recursive function that does it in one functional expression:
const extractToArray = (data, prop) => Object(data) !== data ? []
: Object.values(data).flatMap(v => extractToArray(v, prop))
.concat(prop in data ? data[prop] : []);
var somedata = {foo: {bar: [{baz: [{someprop: 'a'},{someprop: 'b'},{someprop: 'c'}]},{baz: [{someprop: 'd'},{someprop: 'e'},{someprop: 'f'}]}]}}
console.log(extractToArray(somedata, "someprop"));
This is reusable in the sense that it also works when the property is not always present, or not always at the same depth within the data structure.
For others with similar question, I am adding a more generic (but possibly a bit less efficient) alternative using the JSON.parse reviver parameter
var arr = [], obj = {foo:{bar:[{baz:[{someprop:"a"},{someprop:"b"},{someprop:"c"}]},{baz:[{someprop:"d"},{someprop:"e"},{someprop:"f"}]}]}}
JSON.parse(JSON.stringify(obj), (k, v) => k === 'someprop' && arr.push(v))
console.log(arr)
This question already has answers here:
Simplest way to copy JS object and filter out certain properties
(6 answers)
Remove key-value pair from JSON object
(7 answers)
Javascript - Removing object key not using delete
(2 answers)
Closed 3 years ago.
What's the best way in JavaScript for returning an object omitting just one or more properties?
I can assign a key to undefined and that works for sure, but what if want to completely get rid of that key?
function removeCKey() {
const obj = {a: 'a', b: 'b', c: 'c'}
return {
...obj,
c: undefined,
};
}
const myObj = removeCKey();
Also, I want to avoid creating an intermediate object where I use the spread operator like this
function removeCKey() {
const obj = {a: 'a', b: 'b', c: 'c'}
const {c, ...rest} = newObj
return rest;
}
const myObj = removeCKey();
You can use ES6 object destructuring assignment.
function removeKeys() {
const obj = {
a: 'a',
b: 'b',
c: 'c'
};
// extract property c in variable c
// and rest of the value into res
let { c, ...res } = obj;
return res;
}
console.log(removeKeys())
Just delete what you don't need:
function omit(obj, keys) {
const newObj = { ...obj }; // shallow copy...
keys.forEach(key => {
delete newObj[key]; // ... and `delete`.
});
return newObj;
}
omit({a: 'a', b: 'b', c: 'c'}, ['c']);
outputs
{ a: 'a', b: 'b' }