How can I multiply every nested value of this object by X (e.g. 0.5)?
const myObject = {
base: {
serving: {
size: 100
}
},
fat: {
acids: {
monoUnsaturatedFattyAcids: 12
polyUnsaturatedFattyAcids: 3
saturatedFattyAcids: 2
},
}
}
The object is sometimes nested up to 10 levels deep.
You could define a generator that will provide an iterator over every nested key/value pair (together with the nested object), so that you can do what you want with it inside a for loop:
function * iter(obj) {
for (let [key, value] of Object.entries(obj)) {
if (Object(value) !== value) yield [obj, key, value];
else yield * iter(value);
}
}
// demo
const myObject = {
base: {
serving: {
size: 100
}
},
fat: {
acids: {
monoUnsaturatedFattyAcids: 12,
polyUnsaturatedFattyAcids: 3,
saturatedFattyAcids: 2
},
}
};
for (let [obj, key, value] of iter(myObject)) {
if (typeof value === "number") obj[key] *= 0.5; // multiply by 0.5
}
// The object has been mutated accordingly
console.log(myObject);
function modifyValues(obj) {
for (let key in obj) {
if (typeof obj[key] === "object") {
modifyValues(obj[key]);
}else {
obj[key] = obj[key] * 0.5;
}
}
return obj;
}
console.log(modifyValues({
"a": 5,
"b": {
"c": 10
},
"d": {
"e": 15,
"f": {
"g": 20
}
}
}))
As suggested here's an explanation:
You can try something like a function that recursively iterates through the properties of an object and depending on said property its type, multiply or call our recursive function again.
These are the steps the function takes:
We use the Object.keys method to get an array containing all property names as strings of our object
We iterate through our keys array
for every key we check if obj[key] its value is either a number or something else.
note about obj[key]: by using square braces you can access properties of an object by passing a string. e.g obj['base'] is equivalent to obj.base
if it's type is indeed number, multiply obj[key] by 0.5! Don't forget to actually assign the value to the property.
if it ain't a number, call the function again, but this time we use the object stored in obj[key].
e.g. when you pass myObject to the function, the first key will be base, obj.base contains an object, so we call recursiveMultiplication(obj.base) and the cycle continues.
until every recursiveMultiplication call runs out of keys to iterate through.
When all is said and done, the original object should contain mutated values.
If you don't wish to mutate you should clone the object using something like rfdc. using {...spread} won't cut it for nested objects.
const myObject = {
base: {
serving: {
size: 100
}
},
fat: {
acids: {
monoUnsaturatedFattyAcids: 12,
polyUnsaturatedFattyAcids: 3,
saturatedFattyAcids: 2
}
}
};
const recursiveMultiplication = (obj) => {
Object.keys(obj).forEach(key => typeof obj[key] === "number" ? obj[key] = obj[key] * 0.5 : recursiveMultiplication(obj[key]))
return obj;
};
console.log(recursiveMultiplication(myObject));
I think the best is to use a library to ease the traverse of the nested object.
const _ = require('lodash')
const myObject = {
base: {
serving: {
size: 100
}
},
fat: {
acids: {
monoUnsaturatedFattyAcids: 12,
polyUnsaturatedFattyAcids: 3,
saturatedFattyAcids: 2
},
}
}
const newObjValue = _.cloneDeepWith(myObject, x => typeof x === 'number'? x*0.5: undefined)
console.log(newObjValue)
Here is quick solution. I have not added cases for arrays. need to add them if you expect arrays at the top level or nested inside.
const myObject = {
base: {
serving: {
size: 100
}
},
fat: {
acids: {
monoUnsaturatedFattyAcids: 12,
polyUnsaturatedFattyAcids: 3,
saturatedFattyAcids: 2
},
}
}
function isArray ( obj ) {
return isObject(obj) && (obj instanceof Array);
}
function isObject ( obj ) {
return obj && (typeof obj === "object");
}
function recursiveMultiplyNumberFields(myObject, X){
//Assuming that at the top level, what you pass on is a dictionar object. If it could be arrays as well, need to handle more cases
for (key in myObject){
if (isNaN(myObject [key])==false){
myObject[key] = X*myObject[key];
}
else if(isArray(myObject [key])){
/*not taken care as of now. Need to do if ararys are expected inside*/
}
else if(typeof myObject [key] === 'object' && myObject [key] !== null){
recursiveMultiplyNumberFields(myObject [key],X)
}
else{
//not a number and not a object. So need not do anything
}
}
}
console.log("Before mult",myObject);
recursiveMultiplyNumberFields(myObject,5);
console.log("After mult",myObject);
Related
I don't know if the question is right, but I want to do the following, I want the properties of "variable" to become part of the variable day.
The object being as follows: {seg: 60, min:1, dias: 7, semana: 1}
Remaining the object of the following way: Take into consideration that the object inside the object could be anyone and it does not have to be the property "variable" for what I would like to make it dynamic, reason why an arrangement like delete dia.variable and later to merge would not serve me.
With the code that I show you I have only obtained that the result is: {seg: 60, min:1, variable:{dias: 7, semana: 1}, dias: 7, semana: 1}
Any ideas on how I could do it more efficiently, and above all, do it.
const dia = {seg: 60, min:1, variable:{dias: 7, semana: 1}}
let varia = {}
let newDia = {}
const processJson = () => {
Object.entries(dia).map(([name, value]) => {
if(typeof(value) === 'object'){
varia = value
newDia = {...dia, ...variable}
}
})
}
processJson()
This is a universal method for flatting any object with 2 levels deep. It uses the array reduce method and the Object.keys() function:
const dia = { seg: 60, min: 1, variable: {dias: 7, semana: 1} }
function flatObject(o) {
return Object.keys(o).reduce((result, key) => {
// If there is a nested object, flat the object
if (typeof o[key] === 'object' && ! Array.isArray(o[key]) && o[key] !== null) {
for (const inKey in o[key]) {
result[inKey] = o[key][inKey];
}
}
// Just copy the value
else {
result[key] = o[key];
}
// Return accumulator
return result;
}, {});
}
console.log(flatObject(dia))
Start of by using a destructuring assignement to extract the seg, min and variable properties from the dia object.
const { seg, min, variable } = dia;
Then create a new object in which you set the seg and min properties with the destructured properties. For the variable property, use the spread syntax to place the properties of variable inside the same object.
const result = {
seg,
min,
...variable
};
const dia = {
seg: 60,
min: 1,
variable: {
dias: 7,
semana: 1
}
};
const { seg, min, variable } = dia;
const result = {
seg,
min,
...variable
};
console.log(result);
Is there a way to change all properties of an object to a given value, for example to 0? Will it work with nested objects?
I guess it's a noob question, but i started messing around with js only few days ago.
EDIT:
basically it looks like this:
var obj1 = {
obj11: {
a11: 1
b11: 2
c11: 321
},
obj12: {
a12: 31
b12: 65
c12: 8776
}
}
All those values are affected by some other functions. I wanted to make a "reset" function that would set all those values to 0. My expected output is:
{
obj11: {
a11: 0
b11: 0
c11: 0
},
obj12: {
a12: 0
b12: 0
c12: 0
}
}
let obj1 = {
obj11: {
a11:1,
b11:2,
c11:321,
},
obj12: {
a12:31,
b12:65,
c12:8776,
},
};
// Declare a function with a single argument o.
function reset(o) {
// Loop through all of the properties of the argument object o
for([key, value] of Object.entries(o)) {
const t = typeof value;
switch(t) {
// If the current property has an object value, handle that recursively.
case 'object': reset(value); break;
// If the current property has a numeric value, set the value to 0.
case 'number': o[key] = 0; break;
// Otherwise print some status information.
default: console.log('The property '+key+'is of an unhandled type ('+t+').');
}
}
}
reset(obj1);
// Print the result for convenience.
console.log(JSON.stringify({obj1}));
One way to do this is to take advantage of JSON.stringify(). Using its replacer argument, you can specify how each value should be transformed. This method will also recursively traverse your object, allowing you to change all values. As this function converts your object to a string, you'll need to convert it back using JSON.parse():
const obj1 = { obj11: { a11: 1, b11: 2, c11: 321 }, obj12: { a12: 31, b12: 65, c12: 8776 } };
const res = JSON.parse(JSON.stringify(obj1, (key, value) => Object(value) === value ? value : 0));
console.log(res);
The above uses an arrow function, which gets passed in a key and a value. This will be called for every key/value in your object. The value that you return from the arrow function is the new resulting value in the new object. In this case, that value is the is 0 when the value isn't an object, otherwise, if it is an object, we just return the original object.
Note: If you have an object type that isn't serializable (such as a function) as one of your values, then this method will remove that key-value pair.
If your object has a consistent structure and doesn't contain infinitely nested objects, you might find it more straightforward to loop over the keys of your obj1 (obj11 and obj12) using a for..in loop, and then the keys of the inner objects which you can obtain by using the currently looped on key from your outer loop:
const obj1 = { obj11: { a11: 1, b11: 2, c11: 321 }, obj12: { a12: 31, b12: 65, c12: 8776 } };
const res = {};
for(const key in obj1) {
res[key] = {};
for(const innerKey in obj1[key]) {
res[key][innerKey] = 0;
}
}
console.log(res);
Finally, you could use a recursive approach, where you use a function to loop the entries (a [[key, value], ...] pair array) of your object, with .map() to convert every value to a 0. You can then use Object.fromEntries() to build your object back together from the entries array. If you encounter an object as one of your values, you can recall this function to apply the same logic to the nested value:
const obj1 = { obj11: { a11: 1, b11: 2, c11: 321 }, obj12: { a12: 31, b12: 65, c12: 8776 } };
const changeVals = (obj, newVal) =>
Object.fromEntries(Object.entries(obj).map(
([key, val]) =>
!Array.isArray(val) && Object(val) === val && typeof val === "object"
? [key, changeVals(val, newVal)]
: [key, newVal]
)
);
console.log(changeVals(obj1, 0));
I have an object that looks like this:
var myObject = { a: { b: [{}], c: [{}, {d: 2}], e: 2, f: {} }, g:{}, h:[], i: [null, 2] }
I want to remove null values and and empty objects (array and objects) so that it looks like:
{ a: {c: [ {d: 2} ], e: 2 }, i: [ 2 ] }
The function should remove null values, empty objects and empty arrays. Any elegant way to do it ?
Here is a function that clean the object recursively. It will loop deeply through all the properties and remove null values, null arrays and null objects:
cleanUpObject(jsonObject: object): object {
Object.keys(jsonObject).forEach(function (key, index) {
const currentObj = jsonObject[key]
if (_.isNull(currentObj)) {
delete jsonObject[key]
} else if (_.isObject(currentObj)) {
if (_.isArray(currentObj)) {
if (!currentObj.length) {
delete jsonObject[key]
} else {
const cleanupArrayObj = []
for (const obj of currentObj) {
if (!_.isNull(obj)) {
const cleanObj = this.cleanUpJson(obj)
if (!_.isEmpty(cleanObj)) {
cleanupArrayObj.push(cleanObj)
}
}
}
if (!cleanupArrayObj.length) {
delete jsonObject[key]
} else {
jsonObject[key] = cleanupArrayObj
}
}
} else {
if (_.isEmpty(Object.keys(jsonObject[key]))) {
delete jsonObject[key]
} else {
jsonObject[key] = this.cleanUpJson(currentObj)
if (_.isEmpty(Object.keys(jsonObject[key]))) {
delete jsonObject[key]
}
}
}
}
}, this)
return jsonObject
}
We don't know what you mean by clean, but from what I understand, you want to remove all null and empty values. This algorithm is straight-forward: recursively check for and remove any empty / null values (which are recursively checked).
function clean(obj) {
// clean array
if (Array.isArray(obj)) {
for (let i=0; i<obj.length; i++) {
if (isNothing(obj[i])) obj.splice(i, 1); // remove value if falsy
else if (typeof obj[i] === 'object') clean(obj[i]); // recurse if it's a truthy object
}
// clean other object
} else {
for (let prop in obj) {
if (!obj.hasOwnProperty(prop)) continue;
if (isNothing(obj[prop])) delete obj[prop]; // remove value if falsy
else if (typeof obj[prop] === 'object') clean(obj[prop]); // recurse if it's a truthy object
}
}
}
// Recursively check for populated or nonnull content. If none found, return `true`. Recursive so [{}] will be treated as empty.
function isNothing(item) {
// null / undefined
if (item == null) return true;
// deep object falsiness
if (typeof item === 'object') {
if (Array.isArray(item)) {
// array -> check for populated/nonnull value
for (let i=0; i<item.length; i++) {
if (!isNothing(item[i])) return false;
}
return true;
}
// other object -> check for populated/nonnull value
for (let prop in item) {
if (!item.hasOwnProperty(prop)) continue;
if (!isNothing(item[prop])) return false;
}
return true;
}
return false;
}
var myObject = { a: { b: [{}], c: [{}, {d: 2}], e: 2, f: {} }, g:{}, h:[], i: [null, 2] };
console.log("Before: " + JSON.stringify(myObject));
clean(myObject);
console.log("After: " + JSON.stringify(myObject));
To reduce repetitive code, one option is to define a function (let's call it itemToBool) that can determine whether a generic value passed to it is truthy, or recursively truthy somewhere, should the value be an array or object. Then, in the function that gets passed the original object (or, gets recursively passed an object or array), you can call that itemToBool function whenever there's a value to validate.
In the case of arrays, map by itemToBool and then filter by Boolean. In the case of objects, reduce the entries of the object into another object: pass each value of the object through itemToBool to recursively transform it (in case the value is an array or object), and if the transformed value has any keys (or is a truthy primitive), assign it to the accumulator. No need to depend a library:
var myObject = {
a: {
b: [{}],
c: [{}, {
d: 2
}],
e: 2,
f: {}
},
g: {},
h: [],
i: [null, 2]
};
// Returns a falsey value if the item is falsey,
// or if the deep cleaned array or object is empty:
const itemToBool = item => {
if (typeof item !== 'object' || item === null) return item;
const cleanedItem = clean(item);
return Object.keys(cleanedItem).length !== 0 && cleanedItem;
};
const clean = obj => {
if (Array.isArray(obj)) {
const newArr = obj.map(itemToBool).filter(Boolean);
return newArr.length && newArr;
}
const newObj = Object.entries(obj).reduce((a, [key, val]) => {
const newVal = itemToBool(val);
if (newVal) a[key] = newVal;
return a;
}, {});
return Object.keys(newObj).length > 0 && newObj;
};
console.log(clean(myObject));
Hmm... you also might abstract the check of the number of keys into a function as well:
var myObject={a:{b:[{}],c:[{},{d:2}],e:2,f:{}},g:{},h:[],i:[null,2]}
// Returns the object / array if it has at least one key, else returns false:
const validObj = obj => Object.keys(obj).length && obj;
const itemToBool = item => (
typeof item !== 'object' || item === null
? item
: validObj(clean(item))
);
const clean = obj => validObj(
Array.isArray(obj)
? obj.map(itemToBool).filter(Boolean)
: Object.entries(obj).reduce((a, [key, val]) => {
const newVal = itemToBool(val);
if (newVal) a[key] = newVal;
return a;
}, {})
);
console.log(clean(myObject));
I have this json object returned from an API that has a few quirks, and I'd like to normalize it so I can process the input the same for every response. These means getting rid of superfluous keys:
Response:
{
_links: {...},
_embedded: {
foo: [
{
id: 2,
_embedded: {
bar: []
}
}
]
}
}
So I'd like to remove all the _embedded keys and flatten it, like so:
{
_links: {...},
foo: [
{
id: 2,
bar: []
}
]
}
This is what I have at the moment, but it only works for the top level and I don't think it'll play well with arrays.
_.reduce(temp1, function(accumulator, value, key) {
if (key === '_embedded') {
return _.merge(accumulator, value);
}
return accumulator[key] = value;
}, {})
Loop in recursion on all of your keys, once you see a key which start with _
simply remove it.
Code:
var
// The keys we want to remove from the Object
KEYS_TO_REMOVE = ['_embedded'],
// The data which we will use
data = {
_links: {'a': 1},
_embedded: {
foo: [
{
id: 2,
_embedded: {
bar: []
}
},
{
id: 3,
_embedded: {
bar: [
{
id: 4,
_embedded: {
bar: []
}
}
]
}
}
]
}
};
/**
* Flatten the given object and remove the desired keys if needed
* #param obj
*/
function flattenObject(obj, flattenObj) {
var key;
// Check to see if we have flatten obj or not
flattenObj = flattenObj || {};
// Loop over all the object keys and process them
for (key in obj) {
// Check that we are running on the object key
if (obj.hasOwnProperty(key)) {
// Check to see if the current key is in the "black" list or not
if (KEYS_TO_REMOVE.indexOf(key) === -1) {
// Process the inner object without this key
flattenObj[key] = flattenObject(obj[key], flattenObj[key]);
} else {
flattenObject(obj[key], flattenObj);
}
}
}
return flattenObj;
}
console.log(flattenObject(data));
So, basically you already have almost all of the code you need. All we have to do is wrap it in a function so we can use recursion. You'll see we only add a check to see if it is an object, if it is, we already have a function that knows how to flatten that object, so we'll just call it again with the key that we need to flatten.
function flatten(temp1) { // Wrap in a function so we can use recursion
return _.reduce(temp1, function(accumulator, value, key) {
if (key === '_embedded') {
return _.merge(accumulator, value);
} else if (value !== null && typeof value === 'object') // Check if it's another object
return _.merge(accumulator, flatten(value)) // Call our function again
return accumulator[key] = value;
}, {})
}
I'll be able to test it in a bit, but this should be what you need.
Got it!
function unEmbed(data) {
return _.reduce(data, function(accumulator, value, key) {
const returnableValue = _.isObject(value) ? unEmbed(value) : value;
if (key === 'embedded') {
return _.merge(accumulator, returnableValue);
}
accumulator[key] = returnableValue;
return accumulator;
}, {});
}
Problem before I was returning return accumulator[key] = returnableValue, which worked out to be return returnableValue.
I have a HUGE collection and I am looking for a property by key someplace inside the collection. What is a reliable way to get a list of references or full paths to all objects containing that key/index? I use jQuery and lodash if it helps and you can forget about infinite pointer recursion, this is a pure JSON response.
fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "d");
// [o.c]
fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "e");
// [o.c.d]
fn({ 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');
// [o.cc,o.cc.dd]
fwiw lodash has a _.find function that will find nested objects that are two nests deep, but it seems to fail after that. (e.g. http://codepen.io/anon/pen/bnqyh)
This should do it:
function fn(obj, key) {
if (_.has(obj, key)) // or just (key in obj)
return [obj];
// elegant:
return _.flatten(_.map(obj, function(v) {
return typeof v == "object" ? fn(v, key) : [];
}), true);
// or efficient:
var res = [];
_.forEach(obj, function(v) {
if (typeof v == "object" && (v = fn(v, key)).length)
res.push.apply(res, v);
});
return res;
}
a pure JavaScript solution would look like the following:
function findNested(obj, key, memo) {
var i,
proto = Object.prototype,
ts = proto.toString,
hasOwn = proto.hasOwnProperty.bind(obj);
if ('[object Array]' !== ts.call(memo)) memo = [];
for (i in obj) {
if (hasOwn(i)) {
if (i === key) {
memo.push(obj[i]);
} else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
findNested(obj[i], key, memo);
}
}
}
return memo;
}
here's how you'd use this function:
findNested({'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');
and the result would be:
[{x: 9}, {y: 9}]
this will deep search an array of objects (hay) for a value (needle) then return an array with the results...
search = function(hay, needle, accumulator) {
var accumulator = accumulator || [];
if (typeof hay == 'object') {
for (var i in hay) {
search(hay[i], needle, accumulator) == true ? accumulator.push(hay) : 1;
}
}
return new RegExp(needle).test(hay) || accumulator;
}
If you can write a recursive function in plain JS (or with combination of lodash) that will be the best one (by performance), but if you want skip recursion from your side and want to go for a simple readable code (which may not be best as per performance) then you can use lodash#cloneDeepWith for any purposes where you have to traverse a object recursively.
let findValuesDeepByKey = (obj, key, res = []) => (
_.cloneDeepWith(obj, (v,k) => {k==key && res.push(v)}) && res
)
So, the callback you passes as the 2nd argument of _.cloneDeepWith will recursively traverse all the key/value pairs recursively and all you have to do is the operation you want to do with each. the above code is just a example of your case. Here is a working example:
var object = {
prop1: 'ABC1',
prop2: 'ABC2',
prop3: {
prop4: 'ABC3',
prop5Arr: [{
prop5: 'XYZ'
},
{
prop5: 'ABC4'
},
{
prop6: {
prop6NestedArr: [{
prop1: 'XYZ Nested Arr'
},
{
propFurtherNested: {key100: '100 Value'}
}
]
}
}
]
}
}
let findValuesDeepByKey = (obj, key, res = []) => (
_.cloneDeepWith(obj, (v,k) => {k==key && res.push(v)}) && res
)
console.log(findValuesDeepByKey(object, 'prop1'));
console.log(findValuesDeepByKey(object, 'prop5'));
console.log(findValuesDeepByKey(object, 'key100'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
With Deepdash you can pickDeep and then get paths from it, or indexate (build path->value object)
var obj = { 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}
var cherry = _.pickDeep(obj,"d");
console.log(JSON.stringify(cherry));
// {"cc":{"d":{}},"dd":{"d":{}}}
var paths = _.paths(cherry);
console.log(paths);
// ["cc.d", "dd.d"]
paths = _.paths(cherry,{pathFormat:'array'});
console.log(JSON.stringify(paths));
// [["cc","d"],["dd","d"]]
var index = _.indexate(cherry);
console.log(JSON.stringify(index));
// {"cc.d":{},"dd.d":{}}
Here is a Codepen demo
Something like this would work, converting it to an object and recursing down.
function find(jsonStr, searchkey) {
var jsObj = JSON.parse(jsonStr);
var set = [];
function fn(obj, key, path) {
for (var prop in obj) {
if (prop === key) {
set.push(path + "." + prop);
}
if (obj[prop]) {
fn(obj[prop], key, path + "." + prop);
}
}
return set;
}
fn(jsObj, searchkey, "o");
}
Fiddle: jsfiddle
In case you don't see the updated answer from #eugene, this tweak allows for passing a list of Keys to search for!
// Method that will find any "message" in the Apex errors that come back after insert attempts
// Could be a validation rule, or duplicate record, or pagemessage.. who knows!
// Use in your next error toast from a wire or imperative catch path!
// message: JSON.stringify(this.findNested(error, ['message', 'stackTrace'])),
// Testing multiple keys: this.findNested({thing: 0, list: [{message: 'm'}, {stackTrace: 'st'}], message: 'm2'}, ['message', 'stackTrace'])
findNested(obj, keys, memo) {
let i,
proto = Object.prototype,
ts = proto.toString,
hasOwn = proto.hasOwnProperty.bind(obj);
if ('[object Array]' !== ts.call(memo)) memo = [];
for (i in obj) {
if (hasOwn(i)) {
if (keys.includes(i)) {
memo.push(obj[i]);
} else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
this.findNested(obj[i], keys, memo);
}
}
}
return memo.length == 0 ? null : memo;
}
Here's how I did it:
function _find( obj, field, results )
{
var tokens = field.split( '.' );
// if this is an array, recursively call for each row in the array
if( obj instanceof Array )
{
obj.forEach( function( row )
{
_find( row, field, results );
} );
}
else
{
// if obj contains the field
if( obj[ tokens[ 0 ] ] !== undefined )
{
// if we're at the end of the dot path
if( tokens.length === 1 )
{
results.push( obj[ tokens[ 0 ] ] );
}
else
{
// keep going down the dot path
_find( obj[ tokens[ 0 ] ], field.substr( field.indexOf( '.' ) + 1 ), results );
}
}
}
}
Testing it with:
var obj = {
document: {
payload: {
items:[
{field1: 123},
{field1: 456}
]
}
}
};
var results = [];
_find(obj.document,'payload.items.field1', results);
console.log(results);
Outputs
[ 123, 456 ]
We use object-scan for data processing tasks. It's pretty awesome once you've wrapped your head around how to use it.
// const objectScan = require('object-scan');
const haystack = { a: { b: { c: 'd' }, e: { f: 'g' } } };
const r = objectScan(['a.*.*'], { joined: true, rtn: 'entry' })(haystack);
console.log(r);
// => [ [ 'a.e.f', 'g' ], [ 'a.b.c', 'd' ] ]
.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
There are plenty more examples on the website.
The shortest and simplest solution:
Array.prototype.findpath = function(item,path) {
return this.find(function(f){return item==eval('f.'+path)});
}