I am attempting to combine 3 arrays of objects while keeping the same indexes of the original array. I am able to accomplish this by using a spread operator method. My current issue is that I am running into issue on internet explorer due to its compatibility. I've been unable to find another way of doing this without using a spread operator method. Is this something that can be done with a method that is compatible with internet explorer?
Here is the current code that I am using :
const revenueArr = [{title: 'online', revenue: 34321, revenueGrowth: 3.2},{title: 'retail', revenue: 321, revenueGrowth: 1.2} ]
const employArr = [ { employGrowth: 0.2 }, {employGrowth: -1.2} ]
const businessArr = [ {businessGrowth: 2.8}, {businessGrowth: 1.6} ]
const allData = revenueArr.map((it, index) => {
return { ...it, ...employArr[index], ...businessArr[index]}
})
console.log(allData)
My expected outcome is the console.log above in the code snippet, where the first index of objects remain the first index after combining them together. Such as:
[
{
"title": "online",
"revenue": 34321,
"revenueGrowth": 3.2,
"employGrowth": 0.2,
"businessGrowth": 2.8
},
{
"title": "retail",
"revenue": 321,
"revenueGrowth": 1.2,
"employGrowth": -1.2,
"businessGrowth": 1.6
}
]
You can use Object.assign() as a replacement for the spread operator. Object.assign() is also not available in Internet Explorer, but you can use a polyfill since it's not new syntax.
// Object.assign polyfill for Internet Explorer
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
const revenueArr = [{title: 'online', revenue: 34321, revenueGrowth: 3.2},{title: 'retail', revenue: 321, revenueGrowth: 1.2} ]
const employArr = [ { employGrowth: 0.2 }, {employGrowth: -1.2} ]
const businessArr = [ {businessGrowth: 2.8}, {businessGrowth: 1.6} ]
const allData = revenueArr.map((it, index) => {
return Object.assign({}, it, employArr[index], businessArr[index]);
})
console.log(allData)
Object.assign should give you the same output, with support for legacy browsers.
const allData1 = revenueArr.map((it, index) => {
return { ...it, ...employArr[index], ...businessArr[index] } // using spread
})
console.log(allData1)
const allData2 = revenueArr.map((it, index) => {
return Object.assign({}, it, employArr[index], businessArr[index]) // using Object.assign
})
console.log(allData2) // same as allData1
You may find this useful https://thecodebarbarian.com/object-assign-vs-object-spread.html
this should be supported everywhere:
revenueArr.map((it, index) => {
let r = {};
for(let [key, value] of Object.entries(it))
r[key] = value;
for(let [key, value] of Object.entries(employArr[index]))
r[key] = value;
for(let [key, value] of Object.entries(businessArr[index]))
r[key] = value;
return r;
})
using the following polyfill:
if (!Object.entries)
Object.entries = function( obj ){
var ownProps = Object.keys( obj ),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array
while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
(Credits: #jfriend00)
Related
const obj = {
obj_abc: '',
obj_def: '',
hello_123: '',
hello_456: ''
}
If I have an object that its property has a certain pattern of prefix how can I split them into multiple arrays?
like
const arr1 = [{
obj_abc: '',
obj_def: ''
}]
const arr2 = [{
hello_123: '',
hello_456: ''
}]
I couldn't think of a way that I can partially match the properties of an object.
My version using Object.keys
const obj = {
obj_abc: 1,
obj_def: 2,
hello_123: 3,
hello_456: 4,
}
const arr1 = [];
const arr2 = [];
Object.keys(obj).forEach(key => {
if (key.match(/hello_.*/)) {
arr1.push({
[key]: obj[key]
});
} else {
arr2.push({
[key]: obj[key]
});
}
});
console.log(arr1, arr2);
You could use reduce method on Object.entries and return one object with separate properties for each similar keys. This assumes you want to match part of the key before _
const obj = {
obj_abc: true,
obj_def: true,
hello_123: true,
hello_456: true
}
const result = Object.entries(obj).reduce((r, [k, v]) => {
const [key] = k.split('_');
if (!r[key]) r[key] = {}
r[key][k] = v
return r;
}, {})
const [r1, r2] = Object.values(result)
console.log(r1)
console.log(r2)
Simplest answer using plain javascript
const a = {
obj_abc:123,
obj_def:456,
hello_123: 123,
hello_456:456
};
const b = {};
for(k in a){
const [key] = k.split('_');
if(!b[key]) {
b[key] = [];
}
b[key].push(a[k]);
}
console.log(b);
i have an nested object as such:
options = {
religous: {
kosher: {
value: 'Kosher',
chosen: false
},
halal: {
value: 'Halal',
active: false
},
},
vegan: {
value: 'Vegan',
active: false
}
}
It contains nested objects of varying sizes. I would like to get an Array containing the values of any value propery. So for the above object the desired output would be:
['Kosher', 'Halal', 'Vegan']
Order doesn't really matter.
I tried to do so recursively as such:
getListOfLabels = obj => {
const lst = []
for (let key in obj) {
if (obj[key].value) lst.push(obj[key].value)
else return getListOfLabels(obj[key])
}
return lst
}
but I keep getting a RangeError: Maximum call stack size exceeded error.
Any suggestions?
The for...in loop assigns the key. To get the value use obj[key]. If the key is value add to lst, if it's an object, call getListOfLabels on it, and spread the results into lst.push():
const options = {"religous":{"kosher":{"value":"Kosher","chosen":false},"halal":{"value":"Halal","active":false}},"vegan":{"value":"Vegan","active":false}}
const getListOfLabels = obj => {
const lst = []
for (let key in obj) {
const val = obj[key] // get the value
if (key === 'value') lst.push(val) // if the key name is "value" push to lst
else if(typeof val === 'object') lst.push(...getListOfLabels(val)) // if type of value is object, iterate it with getListOfLabels and push the results into lst
}
return lst
}
const result = getListOfLabels(options)
console.log(result)
You could take a recursive approach and check if the object contains a value key.
function getValues(object, key) {
if (key in object) return [object[key]];
return Object.values(object).reduce((r, v) => {
if (v && typeof v === 'object') r.push(...getValues(v, key));
return r;
}, []);
}
var options = { religous: { kosher: { value: 'Kosher', chosen: false }, halal: { value: 'Halal', active: false } }, vegan: { value: 'Vegan', active: false } };
console.log(getValues(options, 'value'));
Here's a succinct approach using reduce :-D
const getValues = options => Object.values(options)
.reduce((acc, optionObj) => (
optionObj.value ? [ ...acc, optionObj.value ] : [
...acc,
...Object.values(optionObj).reduce((arr, { value }) => ([ ...arr, value ]), [])
]), [])
I want to find the key of a value in a Javascript nested object with recursion.
Here is my attempt at the function. Are there more elegant ways to implement this?
const foo = { data: { data2: { data3: 'worked' }, data21: 'rand' }, data01: 'rand01' }
function findKey(obj, target) {
let result = null;
if (_.isEmpty(obj) || !_.isObject(obj)){
return null;
}
if (!_.isArray(obj) && Object.keys(obj).length > 0) {
for(let i=0; i < Object.keys(obj).length; i++){
let key = Object.keys(obj)[i];
let val = obj[key];
if (val === target) {
return key;
}else{
result = findKey(val, target);
}
if (result) {break}
}
}
return result;
}
console.log(findKey(foo, 'worked'))
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
For instance is there a way to avoid having to check the value of result to then break?
I feel like result should be able to bubble down the call stack until it returns at the very first function call without having to break.
This was recently brought back up, and one useful technique was not mentioned, generator functions. Often they simplify recursive traversals that need to stop early. Here we break the problem into two functions. One, the generator function nestedEntries gets all the (nested) key-value pairs in the object. The other calls that and returns the first one that matches a target value supplied.
function * nestedEntries (obj) {
for (let [k, v] of Object .entries (obj)) {
yield [k, v]
if (Object (v) === v) {yield * nestedEntries (v)}
}
}
const findKey = (obj, target) => {
for (let [k, v] of nestedEntries (obj)) {
if (v === target) return k
}
return null
}
const foo = {data01: 'rand01', data: {data21: 'rand', data2: { data3: 'worked' } }}
console .log (findKey (foo, 'worked'))
After the few questions made above, it looks like the function should:
Assume the input is always an object.
Assume it might encounter arrays in its way.
Assume it must stop after meeting one value (in case multiple value exists).
The provided input code given by the OP does not handle array cases.
Below code is sampled to work with these sample cases:
Plain nested object structure.
Object with nested arrays of objects or elements.
Below function accepts a second argument which is a callback to evaluate whether the element met is actually the one we're looking for. In this way, it's easier to handle more complex checks.
The recursive approach is kept and, once the key is met, the function simply return to avoid unnecessary searchs.
const foo = { data: { data2: { data3: 'worked' }, data21: 'rand' }, data01: 'rand01' };
const fooWithArrays = {
data: {
data2: {
data3: 'not here'
},
data4: [
{ data5: 'worked' },
{ data6: 'not me' }
]
}
};
const fooWithExpression = {
data: {
data2: {
data3: { id: 15, name: 'find me!' }
},
data21: {
data25: 'not me'
}
}
};
const findKeyByValue = (obj, equalsExpression) => {
// Loop key->value pairs of the input object.
for (var [key, v] of Object.entries(obj)) {
// if the value is an array..
if (Array.isArray(v)) {
// Loop the array.
for (let i = 0; i < v.length; i++) {
// check whether the recursive call returns a result for the nested element.
let res = findKeyByValue(v[i], equalsExpression);
// if so, the key was returned. Simply return.
if (res !== null && res !== undefined) return res;
}
}
// otherwise..
else {
// if the value is not null and not undefined.
if (v !== null && v !== undefined) {
// if the value is an object (typeof(null) would give object, hence the above if).
if (typeof(v) === 'object') {
// check whether the value searched is an object and the match is met.
if (equalsExpression(v)) return key;
// if not, recursively keep searching in the object.
let res = findKeyByValue(v, equalsExpression);
// if the key is found, return it.
if (res !== null && res !== undefined) return res;
}
else {
// finally, value must be a primitive or something similar. Compare.
let res = equalsExpression(v);
// if the condition is met, return the key.
if (res) return key;
// else.. continue.
}
}
else continue;
}
}
}
console.log( findKeyByValue(foo, (found) => found === 'worked') );
console.log( findKeyByValue(fooWithArrays, (found) => found === 'worked') );
console.log( findKeyByValue(fooWithExpression, (found) => found && found.id && found.id === 15) );
You can use Object.entries to iterate all the keys.
Also worth noting, Object.entries also works with Array's, so no
special handling required.
const foo = { data: { data2: { data3: 'worked' }, data21: 'rand' }, data01: 'rand01', arr: [{arrtest: "arr"},'xyz']}
function findKey(obj, target) {
const fnd = obj => {
for (const [k, v] of Object.entries(obj)) {
if (v === target) return k;
if (typeof v === 'object') {
const f = fnd(v);
if (f) return f;
}
}
}
return fnd(obj);
}
console.log(findKey(foo, 'worked'))
console.log(findKey(foo, 'arr'))
console.log(findKey(foo, 'xyz'))
If obj is exactly a plain object with subobjects without arrays, this does the trick.
function findKey(obj, target) {
for (let key in obj) {
const val = obj[key];
if (val === target) {
return key;
}
if (typeof val === "object" && !Array.isArray(val)) {
const ret = findKey(val, target);
if (ret) return ret;
}
}
}
const foo = {
data: { data2: { data3: "worked" }, data21: "rand" },
data01: "rand01",
};
console.log(findKey(foo, "worked"));
console.log(findKey(foo, "bloop"));
You can try regex, if data is just objects without arrays:
const foo = { data: { data2: { data3: 'worked' }, data21: 'rand' }, data01: 'rand01' }
const out = JSON.stringify(foo).match(/"([^{}]+)":"worked"/)[1];
console.log(out);
For simple data processing tasks like this we use object-scan. It's very powerful once you wrap your head around it and makes things a lot cleaner. Here is how you'd solve your questions
(took the liberty to take the input data from #briosheje answer)
// const objectScan = require('object-scan');
const findKeyByValue = (data, fn) => objectScan(['**'], {
abort: true,
rtn: 'property',
filterFn: ({ value }) => fn(value) === true
})(data);
const foo = { data: { data2: { data3: 'worked' }, data21: 'rand' }, data01: 'rand01' };
const fooWithArrays = { data: { data2: { data3: 'not here' }, data4: [{ data5: 'worked' }, { data6: 'not me' }] } };
const fooWithExpression = { data: { data2: { data3: { id: 15, name: 'find me!' } }, data21: { data25: 'not me' } } };
console.log(findKeyByValue(foo, (found) => found === 'worked'));
// => data3
console.log(findKeyByValue(fooWithArrays, (found) => found === 'worked'));
// => data5
console.log(findKeyByValue(fooWithExpression, (found) => found && found.id && found.id === 15));
// => data3
console.log(findKeyByValue(fooWithExpression, (found) => false));
// => undefined
.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
I have added a script that uses ES6 spread operator to the project that gets the params from the url. Unsure how to revert this to the normal vanilla Javascript syntax after I discovered that the project doesn't support ES6.
It's easy to take normal Javascript arrays and use the spread operator but in more complicated instances like this one I cannot make the array return the result without totally changing the script.
getQueryURLParams("country");
getQueryURLParams = function(pName) {
var urlObject = location.search
.slice(1)
.split('&')
.map(p => p.split('='))
.reduce((obj, pair) => {
const [key, value] = pair.map(decodeURIComponent);
return ({ ...obj, [key]: value }) //This is the section that needs to be Vanilla Javascript
}, {});
return urlObject[pName];
};
Thanks to everyone for the replies. After back and forth I realized that the suggestion here that I convert the whole script to ES5 was correct since the browser only complained about that line but other items not ES5 were also problematic.
This is what I had after using ES5:
getQueryURLParams = function(pName) {
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
var urlObject = location.search
.slice(1)
.split('&')
.map(function(element ) {
return element.split('=');
})
.reduce(function(obj, pair) {
const key = pair.map(decodeURIComponent)[0];
const value = pair.map(decodeURIComponent)[1];
return Object.assign({}, obj, { [key]: value });
}, {});
return urlObject[pName];
};
You can use Object.assign():
return Object.assign({}, obj, { [key]: value });
Demo:
const obj = { a: 1 };
const key = 'b';
const value = 2;
console.log(Object.assign({}, obj, { [key]: value }));
FWIW, the { ...obj } syntax is called "Object Rest/Spread Properties" and it's a part of ECMAScript 2018, not ECMAScript 6.
Since you want the syntax for ES5 here is a polyfill for Object.assing() (source: MDN)
// we first set the Object.assign function to null to show that the polyfill works
Object.assign = null;
// start polyfill
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
// end polyfill
// example, to test the polyfill:
const object1 = {
a: 1,
b: 2,
c: 3
};
const object2 = Object.assign({c: 4, d: 5}, object1);
console.log(object2.c, object2.d);
// expected output: 3 5
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)});
}