I'm looking for an elegant solution to this the following:
In many places of my code, I need to find an object that matches an id in an array of objects and then return a property on that object. The referenced id may or may not exist in the array.
The shortest solution I have e up with is the following:
(wanting to get the title of an item if the item exists, otherwise return none)
arrayofObjects = [ { id: 'a3ff3d', title: 'Tesla', color: 'Red' }, { id: 'r43wesd', title: 'AMC', color: 'Rust' }]
wantedObject = { queryTitle: 'Desired Car', id: 'a3ff3d' }
let wantedProperty = arrayOfObjects.some( e => e.id === wantedObject.id) ? arrayOfObjects.find(e => e.id === wantedObject.id).title : 'None Found'
However, this is neither elegant or as efficient as it should be. I'd prefer for it to be a one liner instead of a function.
I'm looking for an elegant solution to this the following:
In many places of my code, I need to find an object that matches an id in an array of objects and then return a property on that object. The referenced id may or may not exist in the array.
The shortest solution I have e up with is the following:
(wanting to get the title of an item if the item exists, otherwise return none)
arrayofObjects = [ { id: 'a3ff3d', title: 'Tesla', color: 'Red' }, { id: 'r43wesd', title: 'AMC', color: 'Rust' }]
wantedObject = { queryTitle: 'Desired Car', id: 'a3ff3d' }
let wantedProperty = arrayOfObjects.some( e => e.id === wantedObject.id) ? arrayOfObjects.find(e => e.id === wantedObject.id).title : 'None Found'
However, this is neither elegant or as efficient as it should be. I'd prefer for it to be a one liner instead of a function.
Share Improve this question edited Sep 15, 2021 at 21:03 Sebastian Simon 19.5k8 gold badges61 silver badges84 bronze badges asked Jan 20, 2019 at 22:15 Matt McCallumMatt McCallum 331 silver badge4 bronze badges 13- 1 You should provide some sample data and expected result. You should be able to use find once, not some + find. It should return a useful value like undefined or null that other processes can use rather than a random string. – RobG Commented Jan 20, 2019 at 22:18
-
1
"one-liner" and "efficient" don't really go hand-in-hand a lot of times. You'll always get more performance out of a normal
for
loop thanArray.prototype
methods. – Patrick Roberts Commented Jan 20, 2019 at 22:21 -
1
Just go for
(array.find(…) || {}).title
– Bergi Commented Jan 20, 2019 at 22:27 - Example data added. Yes, I am thinking that I should be able to use find once, but I'm struggling on how to write it. Returning undefined or null would be acceptable. – Matt McCallum Commented Jan 20, 2019 at 22:29
-
@PatrickRoberts Not true, native array methods are just as fast as
for
loops. – Bergi Commented Jan 20, 2019 at 22:29
4 Answers
Reset to default 7The smallest method is not necessarily the most efficient. I would do it this way:
let wantedProperty = (arrayOfObjects.find(obj => obj.id === wantedObject.id) || {}).title || 'None Found';
Use Array#find and destructuring.
const data = [ { id: 'a3ff3d', title: 'Tesla', color: 'Red' }, { id: 'r43wesd', title: 'AMC', color: 'Rust' }];
function search(idToFind){
const res = data.find(({id}) => id === idToFind);
return res ? res.title : "Nothing found";
}
console.log(search('r43wesd'));
console.log(search('fail'));
Actually, you can create a one line, generalized method for your data structure that you can reuse multiple times:
const arrayOfObjects = [
{id: 'a3ff3d', title: 'Tesla', color: 'Red'},
{id: 'r43wesd', title: 'AMC', color: 'Rust'}
];
const getKey = (a, id, key) => (f = a.find(x => x.id === id)) ? f[[key]] : "Not Found";
console.log(getKey(arrayOfObjects, "a3ff3d", "title"));
console.log(getKey(arrayOfObjects, "r43wesd", "color"));
console.log(getKey(arrayOfObjects, "someid", "color"));
I thought of 2 possible solution. First the one I do NOT remend:
array.reduce((acc, cur) => {
return cur.id == searchedId ? cur.title : acc;
}, "None found");
Especially if you need to use it frequently, avoid "plex" code, even if we are considering one line.
The second option (if you do not really want to use a function) is this one:
Array.prototype.findOrElse = function(cb, objcb, retValue) {
let findElem = this.find(elem => cb(elem));
return objcb(findElem) || retValue;
}
You can call it like this:
array.findOrElse(elem => elem.id == searchedId, elem => elem.title, "None found");
Generally I do not choose this way because I prefer not to touch native objects that js provides, but no one forbids it.
EDIT:
As @PatrickRoberts made me notice, this is not really an answer. I just found 2 possible solutions that for different reasons I do not remend. Functions have this advantage: you do not have to repeat the same code, even if it is one line. Think about a possible situation where you may have to retrieve a different property instead of title
.
On the other hand, customize a function inside the prototype of Array
object is difficult: you try to make that function as generic as possible, with the risk of excessively plicating the function definition.
So why not going with your own defined function?