Native filter in JavaScript with objects? - javascript

To give background of the prompt (this isn't homework, but some questions that someone forwarded me to help with understanding how to use HOF and implementing them correctly so all explanations as well as different approaches to the problem are welcomed):
a) Implement a findPerson method that takes an Array of people and a name String as the target. Each person Object is structred:
{name: 'Erika', gender: 'Female'}
usage example:
findPerson(people, 'Erika') // -> {name: 'Erika', gender: 'Female'}
Constraint: Use filter
My array of objects is as follows:
var people = [
{
name: 'Max',
gender: 'Trans'
},
{
name: 'Sue',
gender: 'Female'
},
{
name: 'Jake',
gender: 'Male'
},
{
name: 'John',
gender: 'Male'
},
{
name: 'Erika',
gender: 'Female'
}
];
The code that I have constructed thusfar is this:
const findPerson = (people, name) => {
people.filter(function(person) {
if(person.name === name){}
return person;
});
};
The problem is that I am running into this error as follows:
should return an object ‣TypeError: Cannot read property 'should' of undefined
should return the proper object ‣TypeError: Cannot read property 'should' of undefined
If anyone could be of assistance of pointing me in the right direction as to how to go about my logic of solving this and where did I go wrong in my code?

filter function should return true or false:
var people = [
{name: 'Max', gender: 'Trans'},
{name: 'Sue', gender: 'Female'},
{name: 'Jake', gender: 'Male'},
{name: 'John', gender: 'Male'},
{name: 'Erika', gender: 'Female'}
];
const findPerson = (people, find) => people.filter(({name}) => name === find)[0];
console.log(findPerson(people, 'Erika'))

const people = [{
name: 'Max',
gender: 'Trans'
},
{
name: 'Sue',
gender: 'Female'
},
{
name: 'Jake',
gender: 'Male'
},
{
name: 'John',
gender: 'Male'
},
{
name: 'Erika',
gender: 'Female'
}
];
const findPerson = (persons, name) => {
return persons.filter((person) => person.name === name);
};
console.log(findPerson(people, 'Erika')[0]);
The issue with your code is that you were not returning the value of calling filter.
filter after it has run, returns an array. It's that returned array that will contain the value that was filtered out.
I did this: findPerson(people, 'Erika')[0] to select the first item from the array since the return value of filter is an array.

Related

Is there a cleaner way to add a new property with unique values to an array

I'm just learning js now (late to the party I know) and I have the following code and I was wondering if it could be written in a cleaner/simpler way?
Also, ideally, instead of using "if (obj.id === 1)" I would like to iterate through the array and add age based on the sequence i.e. [0] would become '32' and so on.
const students = [ // Three objects, each with four properties
{
id: 1,
name: 'Mark',
profession: 'Developer',
skill: 'JavaScript'
},
{
id: 2,
name: 'Ariel',
profession: 'Developer',
skill: 'HTML'
},
{
id: 3,
name: 'Jason',
profession: 'Designer',
skill: 'CSS'
},
];
const studentsWithAge = students.map(obj => {
if (obj.id === 1) {
return {...obj, age: '32'};
} else if (obj.id === 2) {
return {...obj, age: '26'};
} else if (obj.id === 3) {
return {...obj, age: '28'};
}
return obj;
});
console.log(studentsWithAge);
// output
// [
// {
// id: 1,
// name: 'Mark',
// profession: 'Developer',
// skill: 'JavaScript',
// age: '32'
// },
// {
// id: 2,
// name: 'Ariel',
// profession: 'Developer',
// skill: 'HTML',
// age: '26'
// },
// {
// id: 3,
// name: 'Jason',
// profession: 'Designer',
// skill: 'CSS',
// age: '28'
// }
// ]
You can map the array into the object like so:
const ages = ['32', '26', '28'];
const studentsWithAge = students.map(obj => { ...obj, age: ages[obj.id-1] });
You could create an ages array and use the index to map the value to the corresponding object.
const students = [ // Three objects, each with four properties
{
id: 1,
name: 'Mark',
profession: 'Developer',
skill: 'JavaScript'
},
{
id: 2,
name: 'Ariel',
profession: 'Developer',
skill: 'HTML'
},
{
id: 3,
name: 'Jason',
profession: 'Designer',
skill: 'CSS'
},
];
const ages = [32, 26, 28];
const result = students.map((s, i) => {
return { ...s, age: ages[i] }
});
console.log(result);
Your code is true, another way to add ages by the id is the following code. Just use ids as object key and age as value.
The following code check if id exists in the ages const then add it to the studentsWithAge. It works exactly like your code.
const ages = {1: '32', 2: '26', 3: '28'};
const studentsWithAge = students.map(obj => {
if(ages[obj.id]) obj.age = ages[obj.id];
return obj;
});
But if you're sure all ids have age value simpler code like this could be used:
const ages = {1: '32', 2: '26', 3: '28'};
const studentsWithAge = students.map(obj => ({...obj, age: ages[obj.id]}));
The solution depends on how you store the ages data. Here's an example if you keep the ages data in an array of objects, just like you keep the students data.
This approach is easily extended, you can add any other fields related to the student to the object.
students = [
{id: 1,name: 'Mark',profession: 'Developer',skill: 'JavaScript'},
{id: 2,name: 'Ariel',profession: 'Developer',skill: 'HTML'},
{id: 3,name: 'Jason',profession: 'Designer',skill: 'CSS'}];
extraInfo = [{id: 1, age:32}, {id:2, age: 26}, {id:3, age: 33}];
const result = students.map((s)=>
({ ...s, ...extraInfo.find((a) => a.id === s.id) })
);
console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}

How to nest element of an object inside the same object in javascript?

I created a form to get some info from User, and I want to move some of their info into a nested object. the reason why is to better organize my data later in front-end.
As a simple example, how to create the following "newInfo" out of "oldInfo" in JavaScript?
oldInfo = {
name: 'John',
Age: '32',
friend1: 'Michael',
friend2: 'Peter',
};
newInfo = {
name: 'John',
Age: '32',
friends: {
friend1: 'Michael',
friend2: 'peter',
},
};
I'm sure this must be a repeated and simple topic, but I couldn't find any as I didn't know what keyword to search for.
You could explicitly assign it
const oldInfo = {
name: "John",
Age: "32",
friend1: "Michael",
friend2: "Peter",
}
const newInfo = {
name: oldInfo.name,
Age: oldInfo.Age,
friends: {
friend1: oldInfo.friend1,
friend2: oldInfo.friend2,
},
}
console.log(newInfo)
You can do this easily with spread operator:
const { name, Age, ...friends } = oldInfo;
newInfo = { name, Age, friends };
It simply extracts all fields except name and age as friends.
Example:
const oldInfo = {
name: 'John',
Age: '32',
friend1: 'Michael',
friend2: 'Peter',
};
const { name, Age, ...friends } = oldInfo;
const newInfo = { name, Age, friends };
console.log(newInfo);
If you have a dynamic number of friend: name key-value pairs and other properties that shouldn't be nested into friends then you can use Object.entries and reduce:
const oldInfo = {
name: 'John',
Age: '32',
friend1: 'Michael',
friend2: 'Peter',
};
const newInfo = Object.entries(oldInfo).reduce((acc, [k, v]) => {
if(k.startsWith('friend')) {
acc.friends ? acc.friends[k] = v : acc.friends = {[k]: v};
} else {
acc[k] = v;
}
return acc;
},{});
console.log(newInfo);

Filtering object keys inside an array of objects

Let's assume I'm obtaining an array of objects from a Node Repository, for example:
results = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
How can I filter every object taking only the keys I need, for example avoiding 'age' key?
filteredResults = [
{
name: "John",
surname: "Fool",
},
{
name: "Erik",
surname: "Owl",
}
]
I've already obtained this by creating another empty array and populating it by looping on the original one, but in case of large-data this would be heavy.
repository.retrieve((error, result) => {
let filteredData = [];
result.forEach(r => {
filteredData.push({
name: r.name,
description: r.description,
});
});
});
In SQL, I would obtain it this way:
SELECT `name, description` FROM results;
You can just rebuild the object as you want
{
name: rec.name,
surname: rec.surname
}
const results = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
const result = results.map((rec) => {
return {
name: rec.name,
surname: rec.surname
}
})
console.log(result)
Or delete fields that is useless
const results = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
const result = results.map((rec) => {
delete rec.age
return rec
})
console.log(result)
I suggest you can tell more about what you will need to perform on the output to get the answer that can help.
Case 1. if your original list will survive and you accept your "modified list" to always follow the original list, you may use a generator to wrap your original object, by always not returning those extra properties.
Case 2. if you really want a query system, you may try using real DB thing such as levelDB
Case 3. if you need to display the modified list, write a simple wrapper to fit the format of each list item
Case 4. if you need to snapshot the modified list as object, the method you already made is already a very reasonable method
Case 5. if you need to snapshot the modified list as another output, you can try to directly obtain such output rather than making the intermediate object
You can use map and reduce to simplify this, which obviates the need to create a new array.
var results = [ { name: "John", surname: "Fool", age: 22 }, { name: "Erik", surname: "Owl", age: 38 } ];
let keys = ['name', 'surname'];
var filtered = results.map(obj=>
keys.reduce((acc,curr)=>(acc[curr]=obj[curr],acc), {}));
console.log(filtered);
You can also use object destructuring.
var results = [ { name: "John", surname: "Fool", age: 22 }, { name: "Erik", surname: "Owl", age: 38 } ];
var filtered = results.map(({name,surname})=>({name,surname}));
console.log(filtered);
Take a look at Array.map.It creates the transformed array.
let arr = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
let result = arr.map((elem) => {
return {
name: elem.name,
surname: elem.surname
}
});
console.log(result);
You can use Array.map() to transform individual elements of the array. And in the callback function use Object destructuring assignment to use only the keys you are interested in and return a new object with only those keys.
let results = [
{ name: "John", surname: "Fool", age: 22 },
{ name: "Erik", surname: "Owl", age: 38 }
];
let modified = results.map(({name, surname}) => ({name, surname}));
console.log(modified);

Is my Object returning a hidden 'null' value?

My code seems to return a null value that isn't explicitly declared in the object.
What I'm trying to program is a code that will go through an array of objects, find which value is null, then add a 'question' key to equal to "Hi, could you please provide your 'key'. " Finally I would like to return the array of objects with the question key.
Please see the code below:
var list1 = [
{ firstName: null, lastName: 'I.', country: 'Argentina', continent: 'Americas', age: 35, language: 'Java' },
{ firstName: 'Lukas', lastName: 'X.', country: 'Croatia', continent: 'Europe', age: 35, language: null },
{ firstName: 'Madison', lastName: 'U.', country: 'United States', continent: 'Americas', age: 32, language: 'Ruby' }
];
function askForMissingDetails(list) {
for (let i = 0; i < list.length; i++) {
for (var prop in list[i]) {
if ( list[i].prop == null)
list[i]['question'] = `Hi, could you please provide your ${prop}.`;
else
list.splice(i,1);
}
}
return list;
}
console.log(askForMissingDetails(list1))
The output I get is :
[
0: {
firstName: null
lastName: "I."
country: "Argentina"
continent: "Americas"
age: 35
language: "Java"
question: "Hi, could you please provide your question."
}
1: {
firstName: "Lukas"
lastName: "X."
country: "Croatia"
continent: "Europe"
age: 35
language: null
question: "Hi, could you please provide your question."
}
2: {
firstName: "Madison"
lastName: "U."
country: "United States"
continent: "Americas"
age: 32
language: "Ruby"
question: "Hi, could you please provide your language."
}]
It looks like you're confusing ways to access objects. Firstly, you're reading list[i].prop. This will look for a property quite literally called prop. To fix this, change that to list[i][prop]. The square brackets in this case represent dynamic lookup. Rather than looking for the prop key, you are looking for the key that is the value of prop.
I using reduce to create a new list with the property question to keep in array if have multiple null values in your objects:
var list1 = [
{
firstName: null,
lastName: "I.",
country: "Argentina",
continent: "Americas",
age: 35,
language: "Java"
},
{
firstName: "Lukas",
lastName: "X.",
country: "Croatia",
continent: "Europe",
age: 35,
language: null
},
{
firstName: "Madison",
lastName: "U.",
country: "United States",
continent: "Americas",
age: 32,
language: "Ruby"
},
{
firstName: "Christian",
lastName: null,
country: "Perú",
continent: null,
age: 32,
language: null
}
];
// using list1 as context to apply reduce to be saved on myNewList
const myNewList = list1.reduce((acc, item) => {
// itering keys names of the current object
Object.keys(item).forEach(key => {
// if the current key name his value is null
if (!item[key]) {
// if haven't a key name called question, i create it as a new empty array
if (!item.question) item.question = [];
// pushing into the array the message with the current key name(because is null)
item.question.push(`Hi, could you please provide your ${key}.`);
}
});
// pushing into the accumulator the current object
if (item.question) acc.push(item);
return acc;
}, []);
console.log(myNewList);
let result = list1.reduce((acc, list) => {
let missedKey = "";
for(let key in list){
if(!list[key]) missedKey = key
}
if(missedKey) {
list.question = `Hi, could you please provide your ${missedKey}.`
acc.push(list)
};
return acc;
}, []);
What I believe you're after is a map / reduce operation.
You want to alter your original array to include questions where there are null values ("map") and filter out the entries that are complete ("reduce").
This can all be accomplished using Array.prototype.reduce()
const list = [{"firstName":null,"lastName":"I.","country":"Argentina","continent":"Americas","age":35,"language":"Java"},{"firstName":"Lukas","lastName":"X.","country":"Croatia","continent":"Europe","age":35,"language":null},{"firstName":"Madison","lastName":"U.","country":"United States","continent":"Americas","age":32,"language":"Ruby"}]
const missingDetail = list.reduce((arr, item) => {
// find first null value entry
let [ missing ] = Object.entries(item).find(([ prop, val ]) => val === null) || []
if (missing) {
// missing contains the property name of the first null value
// push new item-with-question object to the final array
arr.push({
...item,
question: `Hi, could you please provide your ${missing}`
})
}
return arr
}, [])
console.info(missingDetail)

sort array of objects based on string

Suppose we have an array like
var a = [
{ name: 'Tom', surname: 'TestAsIvanov' },
{ name: 'Kate', surname: 'Ivanova' },
{ name: 'John', surname: 'Alivanov' },
{ name: 'Ivan', surname: 'Ivanov' }
]
I need to sort this array by surname field based on a provided string, e.g.:
for 'iva' the pattern array should be sorted as follows
var newA = [
{ name: 'Ivan', surname: 'Ivanov' },
{ name: 'Kate', surname: 'Ivanova' },
{ name: 'John', surname: 'Alivanov' },
{ name: 'Tom', surname: 'TestAsIvanov' },
]
for 'a' the pattern array should be sorted as follows
var newA = [
{ name: 'John', surname: 'Alivanov' },
{ name: 'Ivan', surname: 'Ivanov' },
{ name: 'Kate', surname: 'Ivanova' },
{ name: 'Tom', surname: 'TestAsIvanov' },
]
So arrays should be ordered by string pattern provided. How is it possible to implement this?
I've made a simple sort script for that. I don't know if it is the best way because I had to use two sort() methods, one to sort alphabetically(taken from here) and another to simulate a LIKE 'string%'(comparing to SQL) to get your condition:
var queryString = "iva";
a = a.sort(function(a, b) {
var s1 = a.surname.toUpperCase().indexOf(queryString.toUpperCase());
var s2 = b.surname.toUpperCase().indexOf(queryString.toUpperCase());
return (s1 > -1 && s1 > s2);
});
Fiddle with full code
At least it worked with both examples you provided, but I'm not sure if it is all you need.

Categories

Resources