Get values from an array of objects - javascript

I am looping through my array to get the corresponding field value:
var someFun = function (nm) {
var names = [{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}];
for (var i=0; i < names.length; i++) {
if (names[i].name === nm) return names[i].age;
}
};
var username = 'tom';
var printme = someFun(username);
console.log('hey: ', printme)
How can I do the same using Object.keys(), or map, or forEach? Much cleaner and ES6 compliant.

Simply use find
([{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}].find( (s)=> s.name=="tom" )||{}).age //10
([{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}].find( (s)=> s.name=="tom2" )||{}).age //undefined
Demo
var names = [{
name: 'joe',
age: 'nine'
}, {
name: 'tom',
age: 'ten'
}];
function getAge(names, name) {
return (names.find((s) => s.name == name) || {}).age;
}
console.log(getAge(names, "tom"))
console.log(getAge(names, "tom2"))

You can use array.prototype.find:
var names = [{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}];
var someFun = (nm) => {
var found = names.find(el => el.name === nm);
return found && found.age || null;
}
console.log(someFun('tom'));

From Array.prototype.find()
The find() method returns the value of the first element in the array
that satisfies the provided testing function.
If there are multiples objects with the same name?
With Array.prototype.filter()
var names = [{
name: 'joe',
age: 9
},
{
name: 'tom',
age: 10
},
{
name: 'frank',
age: 9
},
{
name: 'joe',
age: 15
}
];
function getData(arr, search) {
// Filter array of objects by a search pair
return arr.filter(o => o[search[0]] === search[1]);
}
function listBy(arr, k) {
// Output values from an array of objects by a key as a comma separated string
return arr.map(o => o[k]).join(",");
}
console.log(getData(names, ["name", "joe"]));
console.log(listBy(getData(names, ["name", "tom"]), "age"));
console.log(listBy(getData(names, ["age", 9]), "name"));

IE doesn't support find, check the Browser compatibility. Maybe you don't need to support IE, but it's still a gets 3.74% of global usage as of Oct 2017. However, it does support filter.
DEMO
var users = [
{ name: "Bill", age: 'nine' },
{ name: 'Tedd', age: 'ten' }
];
function getAgeFromUsers(name) {
const arr = users.filter(u => u.name === name);
return !!arr.length ? arr[0].age : "That user ain't here";
}
console.log(getAgeFromUsers('Tedd'));
console.log(getAgeFromUsers("Lion 'O"));

var someFun = nm => {
const names = [{name: 'joe', age: 'nine'}, {name: 'tom', age: 'ten'}];
const foundName = names.find(name => name.name === nm)
return foundName ? foundName.age : null
};
This replicates what you have above. Although i would personally return the object then age the age from that instead of just returning the age.

Related

search for a specific property in array of objects and return boolean

lets say i have an array of objects
let arr = [
{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
and an object
let obj = {
name: "bill",
age: 55
}
and i want to search all arr objects to find anyone with the same age as obj.age and return a boolean depending whether it includes a same property or not.
i can obviously do :
let find = arr.filter(i => i.age === obj.age);
let bool = find.length > 0 && true;
but is there a way to call a method (lodash,plain js or whatever) to just get this by design like method(arr,obj.age) //returns true ?
let arr = [
{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
let obj = {
name: "bill",
age: 55
}
let find = arr.filter(i => i.age === obj.age);
let bool = find.length > 0 && true;
console.log(bool)
You can use some. So basically it will return a boolean value if any of the object property in array matches the required value
let arr = [{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
let obj = {
name: "bill",
age: 55
}
const val = arr.some(item => item.age === obj.age);
console.log(val)
we can do it in two ways. we can use the some function and get the boolean directly or by find function, we can convert it to a boolean using !! operator.
let arr = [{
name: "john",
age: 22
},
{
name: "george",
age: 55
}
];
let obj = {
name: "bill",
age: 55
}
const val1 = arr.some(item => item.age === obj.age);
console.log(val1)
const val2 = !!arr.find(item => item.age === obj.age);
console.log(val2)

creating Object with different data

I was wondering if there's a way to create an object with changeable data.
Eg:
pearson = {
name: "",
age: 0
}
Can I do something like a loop that each time it changes these 2 variables and assign the whole object with the data into an array, but each time the object will hold the updated data?
Something like:
let pearson = { name: '', age: 20 }
const pearsonsList = [{name: 'dave', age: 20}, {name: 'jessy', age: 30}]
let arr = []
pearsonsList.forEach((e) =>{
pearson.name = e.name
pearson.age = e.age
arr.push(pearson)
})
console.log(arr[0])
/* this what arr[0] holds
{
"name": "jessy",
"age": 30
}*/
how to make arr[0] have a different value than arr[1] where the object data always get overridden ?
The main problem here is your arr is storing the reference to your pearson object, which gets modified each time you set it, even after you push them into your arr.
A solution would be to construct a new object each time before pushing it in.
const pearsonsList = [{name: 'dave', age: 20}, {name: 'jessy', age: 30}]
let arr = []
pearsonsList.forEach((e) =>{
let pearson = { name: '', age: 20 }
pearson.name = e.name
pearson.age = e.age
arr.push(pearson)
})
An optional, and cleaner solution would be to use .map instead of .forEach too
const pearsonsList = [{name: 'dave', age: 20}, {name: 'jessy', age: 30}]
let arr = pearsonsList.map((e) =>{
let pearson = { name: '', age: 20 }
pearson.name = e.name
pearson.age = e.age
return person;
})

how to verify if a property is null in a filter method

I have a list of objects and I have to search them by id and name. Some of my objects have 'name': null and I get an error
Cannot read property 'includes' of null
Object.keys(result).forEach(key => {
if (this.filters.searchBy && this.filters.searchBy.length) {
result[key] = result[key].filter(r =>
this.filters.searchBy.includes(r.id) ||
r.name.includes(this.filters.searchBy));
}
});
I have tried
if (r.name !== null) {
}
but it is not a correct syntax
Optional Chaining & Arrow Functions
You can use ?. to avoid having to check nulls on properties. Also, you can use arrow functions to easily filter an array in JavaScript.
Here is some example code:
let list = [
{name: 'John Smith', age: 13},
{name: 'Peter Jones', age: 23},
{name: 'Jane Doe', age: 54},
{name: null, age : 12},
{age: 72}
];
let result = list.filter(i => {
return (
i.name?.startsWith("J") &&
i.age < 40
)
});
console.log(result);
// Returns only "John Smith"
Without Optional Chaining
As Makyen pointed out, you may not be able to us optional chaining. In that case you can just check each field before using it, as shown below.
let list = [
{name: 'John Smith', age: 13},
{name: 'Peter Jones', age: 23},
{name: 'Jane Doe', age: 54},
{name: null, age : 12},
{age: 72}
];
let result = list.filter(i => {
return (
i.name && // If 'name' is null the condition will fail fast
i.name.startsWith("J") &&
i.age < 40
)
});
console.log(result);
// Returns only "John Smith"
I found a function on a different question (https://stackoverflow.com/a/23809123/8779719) which allows you to easily check nested objects. I've slightly modified it to check for nested fields.
function get(obj, key){
return key.split(".").every(function(x) {
if(typeof obj != "object" || obj === null || ! x in obj || !obj[x])
return false;
obj = obj[x];
return true;
});
}
let list = [
{
name: {
firstName: 'John', lastName: 'Smith'
},
age: 13
},
{
name: {
firstName: null, lastName: 'Jones'
},
age: 23
},
{
name: {
lastName: 'Jones'
},
age: 46
}
];
let result = list.filter(i => {
return (
get(i, "name.firstName") &&
i.name.firstName.startsWith("J") &&
i.age < 40
)
});
console.log(result);
// Returns only "John Smith"
Links:
Optional chaining
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
Arrow functions - a good article I wrote about arrow functions
https://dev.to/acroynon/javascript-arrow-functions-explained-3m04
without the if, you simply write:
&& (r.name !== null)
in your expression and the compiler will accept it, or you can use the filter as follows:
.filter( (item) => {
if (whatever_condition) {
return item;
}
});
You can just do:
Object.keys(result).forEach(key => {
if (this.filters.searchBy && this.filters.searchBy.length) {
result[key] = result[key].filter(r => r &&
(r.id && this.filters.searchBy.includes(r.id)) ||
(r.name && r.name.includes(this.filters.searchBy)));
}
});
Have u tried this
if (r.name) {}

Find element and replace it

I want to make a function (or use library) that will search the array of objects find specific one by its property and replace it with the other object. E.g.:
var a = {name: "Jane", age: 29}
var arr = [{name: "Chris", age: 20}, {name: "Jane", age: 45}]
arr.find(person => { if (a.name === person.name) {person = a})
Is there such a function?
Edit:
It would be nice if there is no matched object in array it would push it to an array that object
I can only think of Array#map
var a = {name: "Jane", age: 29}
var arr = [{name: "Chris", age: 20}, {name: "Jane", age: 45}]
arr = arr.map(function(o){
// if names match, return new object
// otherwise, return original object
return o.name == a.name ? a : o;
});
console.log( arr );
You are probably looking for a wrapper around splice.
Your example would look like this:
arr.forEach((elem, index) => {
if (elem.name !== a.name) return
arr.splice(index, 1, a)
})
You could use the find() method, as such:
var jane = {name: "Jane", age: 29}
var persons = [
{name: "Chris", age: 20},
{name: "Jane", age: 45}
];
function findPerson(person) {
return function(element, index, array) {
if(person.name === element.name) {
array[index] = person;
return true;
}
return false;
}
}
persons.find(findPerson(jane));
This would replace the matched person if found and else returns undefined. So you could check if undefined is returned and add the person afterwards.
Since you want to modify the original array, you can use array#forEach(), just iterate through the array and replace the object which matches your a object name.
var a = {name: "Jane", age: 29}
var arr = [{name: "Chris", age: 20}, {name: "Jane", age: 45}]
arr.forEach((person,index) => {
if (a.name === person.name)
arr[index] = a;
})
console.log(arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Merge objects on unique combinations of key-value pairs

I would like a function
combineListOnKeys(listOfObjs, listOfKeys)
that will take this:
var listOfObjs =
[
{ name: john, state: ny, age: 12}
, { name: john, state: ny, age: 22}
, { name: john, state: dc, age: 32}
, { name: john, state: dc, age: 42}
, { name: paul, state: ca, age: 52}
]
var listOfKeys = ["name", "state"]
and returns this:
combineListOnKeys(listOfObjs, listOfKeys)
[
{ "name": john, "state": ny, "age": [12, 22]}
,{ "name": john, "state": dc, "age": [32, 42]}
,{ "name": paul, "state": ca, "age": [52]}
]
I'm essentially looking to match on multiple specified keys that all these objects share, and take the remaining unspecified keys and combine them into a list, thus removing some duplicate information.
I'm using underscore.js, but I cannot find an example of this problem in the docs. Thanks in advance!
Sorry this doesn't conform with your revised requirements for a function but I got started before you revised and put in a lot of effort and I hope this is enough for you to put together your own function. Using underscore's _.reduce and _.each methods in succession (and the _.each can probably be replaced with a second _.reduce, or with _.map -- as usual there's more than one way to do it).
var arr = [
{ name: 'john', state: 'ny', age: 12}
, { name: 'john', state: 'ny', age: 22}
, { name: 'john', state: 'dc', age: 32}
, { name: 'john', state: 'dc', age: 42}
, { name: 'paul', state: 'ca', age: 52}
];
var resultsMap = _.reduce(arr, function(memo, arrEl) {
/*
* var key = JSON.stringify(_.omit(arrEl, 'age'));
*
* From original answer but naively fails to account for Javascript objects not returning in order.
* See "IIFE" below and http://stackoverflow.com/a/28989092/34806
*/
var key = (function() {
var ageOmittedObj = _.omit(arrEl, 'age');
var ageOmittedPairs = _.pairs(ageOmittedObj);
var sortedPairs = _.reduce(_.keys(ageOmittedObj).sort(), function(sortedPairs, key) {
var pair = _.find(ageOmittedPairs, function(kvPair) {return kvPair[0] == key});
sortedPairs.push(pair);
return sortedPairs;
}, []);
return JSON.stringify(sortedPairs)
}) ();
memo[key] = memo[key] || {};
memo[key].ages = memo[key].ages || [];
memo[key].ages.push(arrEl.age);
return memo;
}, {});
var resultsArr = [];
_.each(resultsMap, function(v, k) {
var resultObj = {};
var nameStatePairs = JSON.parse(k);
var nameStateObj = _.object(_.map(nameStatePairs, function(pair){return [pair[0], pair[1]]}));
// compare above to http://stackoverflow.com/a/17802471/34806
resultObj.name = nameStateObj.name;
resultObj.state = nameStateObj.state;
resultObj.age = v.ages;
resultsArr.push(resultObj);
});
console.log(JSON.stringify(resultsArr));
// [{"name":"john","state":"ny","age":[12,22]},{"name":"john","state":"dc","age":[32,42]},{"name":"paul","state":"ca","age":[52]}]
Not in underscore.js, but plain JS. Which should work fine since underscore is a library running on JavaScript.
I would output a new array using array.prototype.map combined with a for loop that test the new array for multiples. Since this is only one dimension deep, we do not need recursion.
var arr = [
{ name: "john", state: "ny", age: 12}
, { name: "john", state: "ny", age: 22}
, { name: "john", state: "dc", age: 32}
, { name: "john", state: "dc", age: 42}
, { name: "paul", state: "ca", age: 52}
]
var arr2d2 = []; //new array that is going to contain the merged values.
arr.map(function(element){
var outerElement = element;
var found = false; //set initially to false. If not found add element to the new array.
for (var i = 0; i < arr2d2.length; i++)
{
if (arr2d2[i].name == outerElement.name && arr2d2[i].state == outerElement.state)
{
found = arr2d2[i]; // save the element.
break; //stop the loop
}
};
if (found)
{
if (found.age != outerElement.age)
{
found.age.push(outerElement.age); //push the age to the new value.
}
}
else
{
outerElement.age = [outerElement.age]; //convert age to an array, like you specified.
arr2d2.push(outerElement); //not found yet. push element;
}
});
document.body.innerHTML += JSON.stringify(arr2d2); //only to display the result. Not part of the solution.

Categories