JavaScript (ReactJS) comparing two Objects - javascript

I have an object with users:
const data = [
{
name: "John",
lastName: "Doe",
email: "stefa#gmail.com",
password: "123",
following: [{ id: "113"}, { id: "111" } }],
id: "112",
},
{
name: "Jane",
lastName: "Doe",
email: "dusica#gmail.com",
password: "123",
following: [{ id: "112" }],
id: "113",
},
{
name: "Mark",
lastName: "Twain",
email: "marko#gmail.com",
password: "123",
following: [],
id: "111",
},
];
As you can see all users have an array named "following", and that array contains id's of users which the user follows. I want to access that array "following" to find out which users are not followed. Let's say that we want to check the "following" array of the first user John Doe with id="112".
const followers = [];
let suggestions = null;
props.users.forEach((user) => {
if (user.id === '112') {
user.following.forEach((item) => {
followers.push(item);
});
}
});
followers.map((item) => {
suggestions = props.users.map((user) => {
if (user.id !== item.id && user.id !== '112) {
console.log(item.id);
return <div>something</div>;
}
});
});
I tried something like this, but the result is not what i expected to be. As i said, i want to return users that are not followed and render them because i want them to be visible so the user can follow them. I hope that i was understandable enough. Thanks.

It's a negative comparison.
So you want to filter out all users that a user IS following.
You can loop through each user and compare it against the following array. If the following array contains the user then don't show it.
const notFollowing = allUsers.filter(user =>
!currentUser.following.some(({ id }) => id === user.id)
);

Related

Filtering an object by multiple arguments(inputs)

I have a lot of inputs, after which my object is supposed to filter, I can hardcode it, but there is probably a smarter way to do it
Filter state :
const [filters, setFilters] = useState<FiltersType>({
login: "",
name: "",
surrname: "",
});
Example data:
const data: UserRow[] = [
{
key: "1",
login: "John#gmail.com",
name: "John",
surrname: "Smith",
role: ["user"],
},
{
key: "2",
login: "Andrew#gmail.com",
name: "Andrew",
surrname: "Johnson",
role: ["user"],
},
];
data.filter((e) => {
if (
(!filters.name || e.name.includes(filters.name)) &&
(!filters.surrname || e.surrname.includes(filters.surrname)) &&
(!e.login ||
e.login.toLowerCase().includes(filters.login.toLowerCase()))
) {
return true;
}
return false;
})
For example, it can be done like this, but as you can see it looks bad and scales poorly when adding new fields, I tried to simplify it using "Object.entries()", but ultimately failed :(. What is the best pattern for such a problem?
You should use some() (logical OR for all the conditions) or every() (logical AND for all the conditions) in combination with filter().
const data = [
{
key: "1",
login: "John#gmail.com",
name: "John",
surrname: "Smith",
role: ["user"],
},
{
key: "2",
login: "Andrew#gmail.com",
name: "Andrew",
surrname: "Johnson",
role: ["user"],
},
];
const filter = {
login: "",
name: "",
surrname: "",
};
const filters = Object.entries(filter);
const filtered = data.filter((user) =>
filters.some(
([key, value]) =>
user[key] && user[key].toString().toLowerCase().includes(value)
)
);
console.log(filtered);
Use some() if you want to include the result if any of the filter conditions is met and use every() if you want to only include a result if all filter conditions are met.
The above will work for simple filters. You can however extend the solution using typeof() or Array.isArray() function etc. to process different types like arrays, nested objects etc. accordingly.

How to remove an object from an array if it has the letter a?

I need to make a function that receives 2 parameters, the first one is an array of a list of users that must contain first name, last name and phone numbers, at least 3 of those users must start with the letter "a", the second parameter is a callback. You must process the array and delete all the users whose name starts with the letter "a". Then send the new processed array to the callback. The callback must show in console, the list of all the names, concatenating first and last name.
const users =
[{
name: 'Diego',
lastname: 'Garcia',
phone: '12343'
},
{
name: 'Camilo',
lastname: 'Garcia',
phone: '12343'
}, {
name: 'ana',
lastname: 'Rodriguez',
phone: '02343'
}, {
name: 'anastasia',
lastname: 'Zapata',
phone: '42343'
}, {
name: 'alejandra',
lastname: 'Perez',
phone: '52343'
}];
const operation2 = (list) => {
let x = [];
let callback = {};
callback = list.find(element => element.name.charAt(0) == 'a');
let l = list.indexOf(callback)
let g = list[l];
console.log(g)
if (callback) {
x = list.splice(l, 1)
} return list
}
console.log(operation2(users))
The code that I made does not work, it is not eliminating all the names that begin with "a", it only eliminates the first object of the array.
Array.find only finds the first match, you should probably filter out the elements you don't want:
const result = list.filter(element => element.name.charAt(0) !== 'a');
const users =
[{
name: 'Diego',
lastname: 'Garcia',
phone: '12343'
},
{
name: 'Camilo',
lastname: 'Garcia',
phone: '12343'
}, {
name: 'ana',
lastname: 'Rodriguez',
phone: '02343'
}, {
name: 'anastasia',
lastname: 'Zapata',
phone: '42343'
}, {
name: 'alejandra',
lastname: 'Perez',
phone: '52343'
}];
function func(list, callback) {
let users = list.filter(u => !u.name.toLowerCase().startsWith('a'));
callback(users)
}
func(users, (users) => {
console.log(users)
})

Output data from object array

I want to output list of user from object. This object is array and when I don't use specific number of user I get invalid data. But when I put number for user in object I get information that I need. My question is, why my code does't work properly and how to output all user?
// Give Users needed types
type typeUsers = { name: string; age?: number };
// List of users
const Users: typeUsers[] = [
{
name: "John",
age: 21,
},
{
name: "Max",
},
];
function UserFunc(Users) {
// If user has age output this
if ("age" in Users) {
console.log(`Name: ${Users.name}, Age: ${Users.age}`);
} else {
console.log(`Name: ${Users.name}`);
}
}
UserFunc(Users);
But also its work when I change last string to UserFunc(Users[number])
First, it's common in javascript to write the variable names in camelCase.
Second, Users is an array of object, so you need to iterate over, to log each object inside.
// Give Users needed types
type typeUsers = { name: string; age?: number };
// List of users
const users: typeUsers[] = [
{
name: "John",
age: 21,
},
{
name: "Max",
},
];
function userFunc(users: typeUsers[]) {
// loop throw users array with `forEach` method
users.forEach(user => {
// If user has age output this
if ("age" in user) {
console.log(`Name: ${user.name}, Age: ${user.age}`);
} else {
console.log(`Name: ${user.name}`);
}
})
}
userFunc(users);
This is a working exmaple
if ("age" in Users) only works with objects, not with arrays. you can loop over the array like that:
// Give Users needed types
type typeUsers = { name: string; age?: number };
// List of users
const Users: typeUsers[] = [
{
name: "John",
age: 21,
},
{
name: "Max",
},
];
function UserFunc(Users: any) {
// If user has age output this
Users.forEach((User: any)=>{
if ("age" in User) {
console.log(`Name: ${User.name}, Age: ${User.age}`);
} else {
console.log(`Name: ${User.name}`);
}
})
}
UserFunc(Users);
Users is an array. So in order to access an element in array you have to do Users[0].name or Users[1].name.
Or, if you want to output all the data, wrap your if else structure in an Array.forEach() like so:
// Give Users needed types
type typeUsers = { name: string; age?: number };
// List of users
const Users: typeUsers[] = [
{
name: "John",
age: 21
},
{
name: "Max"
}
];
function UserFunc(Users: typeUsers[]) {
// If user has age output this
Users.forEach((user) => {
if ("age" in user) {
console.log(`Name: ${user.name}, Age: ${user.age}`);
} else {
console.log(`Name: ${user.name}`);
}
});
}
UserFunc(Users);
The problem is that you are checking for the User property age directly from the array. As others have pointed out, you need to loop through the array to access each of the User object where the check for property age will be valid.
// Give Users needed types
type typeUsers = { name: string; age?: number };
// List of users
const Users: typeUsers[] = [
{
name: "John",
age: 21,
},
{
name: "Max",
},
];
function UserFunc(Users) {
// If user has age output this
for (const user of Users) {
if ("age" in user) {
console.log(`Name: ${user.name}, Age: ${user.age}`);
} else {
console.log(`Name: ${user.name}`);
}
}
}
UserFunc(Users);

How to turn an Array of objects into a nested object?

Hello I try to get this output
{
name: "Saviole",
role: "ceo",
children: [
{
name: "Mary",
role: "supervisorA",
children: [
{name: "Anna", role: "worker"}
]
}, {
name: "Louis",
role: "supervisorB"
}]
}
These are the functions I wrote:
const users = [
{name: "Anna", role: "worker"},
{ name: "Mary", role: "supervisorA" },
{ name: "Louis", role: "supervisorB" },
{ name: "Saviole", role: "ceo" }
];
const recursiveAddToTree = (parent, child, grandChildren, users)=>{
let tree = {};
users.forEach(( user)=>{
if(user.role===parent){
tree ={...user}
} else if(user.role===child){
tree = {...tree, chidren:[...[user]]}
} else {
users.forEach(userChild=>{
if(userChild.role===child){
tree = {...tree, children:[...[{...userChild, chidren: [...[user]]}]]}
}
})
}
})
return tree;
}
const createSchema = users =>{
return recursiveAddToTree("ceo", "supervisorA","worker", users)
}
How do I solve this? I don't understand why it doesn't work as thought
You could take a sorted array where all users are orderd by their role under the direct role above and take an object to get a level of the roles. Then iterate and take an array of level for keeping track of the last user and inser the user according to the role/level.
This approach maintains the given order.
const
users = [
{ name: "Saviole", role: "ceo" },
{ name: "Mary", role: "supervisor" },
{ name: "Anna", role: "worker" },
{ name: "Louis", role: "supervisor" }
],
roles = { ceo: 0, supervisor: 1, worker: 2 },
tree = [],
levels = [tree];
users.forEach(user => {
const level = roles[user.role];
if (!levels[level]) {
const
temp = levels[level - 1],
last = temp[temp.length - 1];
levels[level] = [];
last.children = levels[level];
}
levels[level].push(user);
});
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I saw 2 issue in your code:
the foreach will process the users one by one, finishing by the last one: the ceo. But in your code if the processed user is the ceo your tree object is replaced by the user, so all your previous modifications are erased (I think it's the most important issue)
the roles of the supervisors are "supervisorA" and "supervisorB", but you're checking if the role is "supervisor", it'll never match, you should check if the role start with "supervisor"

Build JS arrays by key into one - find a best solution

What's the best solution to mapping 2 multiple arrays to build one by key?
I have 1 array with users who have their profile data like
var users = [{id:5, name:'Alex'}, {id:17, name:'Tom'}, {id:11, name:'John'}];
Also I have another one array of cars with key user_id To determine which machine belongs to which user.
var cars = [{id:333, name:'Nissan', user_id:11}, {id:444, name:'Toyota', user_id:17}, {id:555, name:'BMW', user_id:999}];
So we can see that Tom have Toyota and John have Nissan.
So result should be
a new array with mapped result
[{
"profile": {
"id": 17,
"name": "Tom"
},
"car": {
"id": 444,
"name": "Toyota",
"user_id": 17
}
}, {
"profile": {
"id": 11,
"name": "John"
},
"car": {
"id": 333,
"name": "Nissan",
"user_id": 11
}
}]
My solution is use forEach throw users and sub forEach throw cars and there compare user.id with car.user_id
https://jsfiddle.net/r7qwke1f/37/
You could use a two loop approach instead of a nested loop approach by collecting first all users in a hash table anbd then iterate all cars and if a user is available, then create a new result set.
var users = [{ id: 5, name: 'Alex' }, { id: 17, name: 'Tom' }, { id: 11, name: 'John' }],
cars = [{ id: 333, name: 'Nissan', user_id: 11 }, { id: 444, name: 'Toyota', user_id: 17 }, { id: 555, name: 'BMW', user_id: 999 }],
hash = {},
result = [];
users.forEach(function (user) {
hash[user.id] = user;
});
cars.forEach(function (car) {
if (hash[car.user_id]) {
result.push({ profile: hash[car.user_id], car: car });
}
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another solution
const mappedUsersCars = users.map((user) => ({
profile: user,
car: cars.filter((car) => car.user_id === user.id)[0]
}))
You can use reduce() and find() methods to get desired result.
var users = [{id:5, name:'Alex'}, {id:17, name:'Tom'}, {id:11, name:'John'}];
var cars = [{id:333, name:'Nissan', user_id:11}, {id:444, name:'Toyota', user_id:17}, {id:555, name:'BMW', user_id:999}];
var r = users.reduce(function(r, e) {
var car = cars.find(a => a.user_id == e.id);
if(car) r.push({profile: e, car: car});
return r;
}, [])
console.log(r)
There are basically two methods you would want to use. You want to map the users to the cars, so you want to find a car for the user you are referring to
const result = users.map((user) => {
const car = cars.find(car => car.user_id === user.id);
return {
profile: user,
car,
}
})

Categories

Resources