Get an array from nested objects - javascript

i have nested object users
let users = {
'0LsRDanmw1s1KBvZAAAC':
{
name: 'user1',
room: 'Lobby'
},
'Qvd9v0EStnwNe11mAAAD':
{
name: 'user2',
room: 'Music'
},
};
I want to get an array of users where room === 'Lobby'
let onlineUsers = ['user1'];
Thanks in advance
edit:
alot of good solutions thank you guys!

Get values, execute .filter() and then .map().
let users = { '0LsRDanmw1s1KBvZAAAC': { name: 'user1', room: 'Lobby' }, 'Qvd9v0EStnwNe11mAAAD': { name: 'user2', room: 'Music' },};
var onlineUsers = Object.values(users)
.filter(u => u.room === 'Lobby')
.map(u => u.name);
console.log(onlineUsers );
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or you can get values and execute .reduce().
let users = { '0LsRDanmw1s1KBvZAAAC': { name: 'user1', room: 'Lobby' }, 'Qvd9v0EStnwNe11mAAAD': { name: 'user2', room: 'Music' },};
var onlineUsers = Object.values(users)
.reduce((a, u) => (u.room === 'Lobby' ? [...a, u.name] : a), []);
console.log(onlineUsers);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}

You can take the values of the array, filter as desired and map only the name.
var users = { '0LsRDanmw1s1KBvZAAAC': { name: 'user1', room: 'Lobby' }, 'Qvd9v0EStnwNe11mAAAD': { name: 'user2', room: 'Music' } },
result = Object
.values(users)
.filter(({ room }) => room === 'Lobby')
.map(({ name }) => name);
console.log(result);

Combination of Object.values, filter and map:
let users = {'0LsRDanmw1s1KBvZAAAC': { name: 'user1',room: 'Lobby' },'Qvd9v0EStnwNe11mAAAD':{ name: 'user2',room: 'Music' },};
const res = Object.values(users)
.filter( o => o.room === 'Lobby')
.map( o => o.name );
console.log(res);

Use ES8 Object.values() to get all the values from the object, then apply .filter and .map
let users = {
'0LsRDanmw1s1KBvZAAAC':
{
name: 'user1',
room: 'Lobby'
},
'Qvd9v0EStnwNe11mAAAD':
{
name: 'user2',
room: 'Music'
},
};
var onlineUsers = Object.values(users).filter(el => el.room==="Lobby").map(el => el.name);
console.log(onlineUsers);

I still like the old school, old-browser-safe, version of a simple for loop, so for the sake of completeness:
var users = {
'0LsRDanmw1s1KBvZAAAC':
{
name: 'user1',
room: 'Lobby'
},
'Qvd9v0EStnwNe11mAAAD':
{
name: 'user2',
room: 'Music'
},
};
var lobbyUsers = [];
for (var prop in users) {
if (users.hasOwnProperty(prop)) {
if (users[prop].room === 'Lobby') {
lobbyUsers.push(users[prop].name);
}
}
}
console.log(lobbyUsers);

Related

JavaScript​ program that​ displays​ a list​ of​ names​ according​ to​ ​the Subject​ group

let a =
[
{
Name: 'Josh',
Subject: ['Biology', 'Chemistry'],
},
{
Name: 'James',
Subject: ['Chemistry', 'Physics'],
},
{
Name: 'Mary',
Subject: ['Physics', 'Mathematics'],
},
]
const result = a.reduce((groupedSubject, person) => {
const Subject = person.Subject
if(groupedSubject[Subject]== null) groupedSubject[Subject] = []
groupedSubject[Subject].push(person)
return groupedSubject
}, {})
console.log(result)
I was able to group according to the subject, but subject is an array. how do i group it by individual subjects?
You need to iterate Sports array as well.
const
data = [{ Name: 'Ravindra', Sports: ['Chess', 'Cricket'] }, { Name: 'Ravi', Sports: ['Cricket', 'Football'] }, { Name: 'Rishabh', Sports: ['Table-Tennis', 'Football'] }],
result = data.reduce((groupedSports, person) => {
person.Sports.forEach(sport => {
groupedSports[sport] ??= [];
groupedSports[sport].push(person.Name);
})
return groupedSports;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can iterate over all sports and check if it already exists, if not, spread all current entries and add the new persons Name to the array.
let a = [{
Name: 'Ravindra',
Sports: ['Chess', 'Cricket'],
},
{
Name: 'Ravi',
Sports: ['Cricket', 'Football'],
},
{
Name: 'Rishabh',
Sports: ['Table-Tennis', 'Football'],
},
]
const result = a.reduce((groupedSports, person) => {
person.Sports.forEach((sport) => {
groupedSports[sport] = groupedSports?.[sport]
? [...groupedSports[sport], person.Name]
: [person.Name];
});
return groupedSports;
}, {});
console.log(result)

How to conditionally filter the data

I'm writing a small js code where I need to filter the data based on key passed. Here, the main issue is, the data is not consistent(please refer to my code sample).
var users = [{
name: 'paul',
job: 'engineer'
},
{
name: 'John',
job: 'Mechanic'
},
{
name: 'paul',
job: 'Mechanic'
},
{
name: 'George',
job: 'Plumber'
},
{
name: 'John'
},
];
filtersToApply = {
job: 'engineer'
};
returnFilteredList = (users, columnDataToFilter) => {
return users.filter((row) => {
return Object.keys(columnDataToFilter).every(
(propertyName) =>
row[propertyName]
.toString()
.toLowerCase()
.indexOf(columnDataToFilter[propertyName].toString().toLowerCase()) >
-1
);
});
};
console.log(JSON.stringify(returnFilteredList(users, filtersToApply)));
Here I get the error, 'coz, there is no job for the last JSON object in the array. how can I handle this?
You could get the entries of you filter conditions and check with Array#every or Array#some, depending on the need.
const
users = [{ name: 'paul', job: 'engineer' }, { name: 'John', job: 'Mechanic' }, { name: 'paul', job: 'Mechanic' }, { name: 'George', job: 'Plumber' }, { name: 'John' }],
filtersToApply = { job: 'engineer' },
filters = Object.entries(filtersToApply),
result = users.filter(user =>
filters.every(([k, v]) => (user[k] || '').toLowerCase() === v)
);
console.log(result);
If you have an array or only a sting, you need to compare each value and adjust the case in advance.
const
users = [{ name: 'paul', job: 'engineer' }, { name: 'John', job: ['Mechanic', 'Engineer'] }, { name: 'paul', job: 'Mechanic' }, { name: 'George', job: 'Plumber' }, { name: 'John' }],
filtersToApply = { job: 'engineer' },
filters = Object.entries(filtersToApply),
result = users.filter(user =>
filters.every(([k, v]) => []
.concat(user[k] || [])
.map(s => s.toLowerCase())
.includes(v)
)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sometimes row[propertyName] will be undefined. You can use an Optional Chaining operator to avoid the errors:
return Object.keys(columnDataToFilter).every(
(propertyName) =>
row[propertyName]? //<--
.toString()
.toLowerCase()
.indexOf(columnDataToFilter[propertyName].toString().toLowerCase()) >
-1
);
return Object.keys(columnDataToFilter).every(
(propertyName) =>
row[propertyName]|| '' //you can add undefined keys to empty string.
.toString()
.toLowerCase()
.indexOf(columnDataToFilter[propertyName].toString().toLowerCase()) >
-1
);

return the value of the matching items in an array

I have two arrays that I would like to compare and return a respective value of the ones that match.
Taking the 'id' variable as a reference, I want to return all the matching values of fastFood, but only the 'name'.
My expected result is to return Five Guys and KFC, but instead, it returns the entire object.
let id = ['1234'];
let fastFood = [
{_id:'4391', name: "McDonalds"},
{_id:'7654', name: "Burger King"},
{_id:'8765', name: "Dominos"},
{_id:'1234', name: "Five Guys"},
{_id:'9876', name: "Subway"},
{_id:'1234', name: "KFC"}
];
const findFastFood = ids.filter((item) => {
if (item._id.indexOf(id) !== -1) {
return item.name;
}
});
console.log(findFastFood);
Does this help?
let id = ['1234'];
let fastFood = [{
_id: '4391',
name: "McDonalds"
},
{
_id: '7654',
name: "Burger King"
},
{
_id: '8765',
name: "Dominos"
},
{
_id: '1234',
name: "Five Guys"
},
{
_id: '9876',
name: "Subway"
},
{
_id: '1234',
name: "KFC"
}
];
const findFastFood = fastFood.filter((item) => {
if (id.indexOf(item._id) !== -1) {
return item.name
}
}).map(obj => obj.name);
console.log(findFastFood);

Transform an array of data by status

I need to filter an array by property:
Here's the data, which I get from the server:
const mockResults = [
{
user: {
firstName: '1',
lastName: '1'
},
status: 'WRONG'
},
{
user: {
firstName: '2',
lastName: '2'
},
status: 'WRONG'
},
{
user: {
firstName: '3',
lastName: '3'
},
status: 'CORRECT'
}
];
To display the data, I need to transform it to a required by ReactNative SectionList format:
const requiredFormat = [
{
status: 'WRONG',
data: [{ user: {firstName: '1', lastName: '1'}}, { user: {firstName: '2', lastName: '2'}}],
},
{
status: 'CORRECT',
data: [{ user: {firstName: '3', lastName: '3'}}],
},
];
Basically, the mockResults should be sorted by status. There can be maximum of 4 statuses: correct, wrong, missed, chosen. All these statuses should include all the data marked with them.
What is the right way to implement this?
I've tried to filter the array, but I'm stuck at this point:
const transformArray = mockResults.filter(item => {
return {
answerStatus: item.status,
data: [item.user]
}
})
You may walk through the array (using Array.prototype.reduce() method) and create new element of resulting array once you see there's no such with current status or append current element data if one exists:
const mockResults = [{user:{firstName:'1',lastName:'1'},status:'WRONG'},{user:{firstName:'2',lastName:'2'},status:'WRONG'},{user:{firstName:'3',lastName:'3'},status:'CORRECT'}],
result = mockResults.reduce((r,{status, ...rest}) => {
const common = r.find(e => e.status == status)
common ?
common.data.push(rest) :
r.push({status, data:[rest]})
return r
}, [])
console.log(result)
.as-console-wrapper {min-height:100%}
You can use reduce() to achieve that:
const mockResults = [{user: { firstName: '1', lastName: '1'}, status: 'WRONG'},{user: {firstName: '2',lastName: '2'},status: 'WRONG'},{user: { firstName: '3',lastName: '3'},status: 'CORRECT'}];
const result = mockResults.reduce((a, {user, status}) => {
const temp = a.find(e => e.status === status);
if (temp) {
temp.data.push({user});
} else {
a.push({status, data: [{user}]});
}
return a;
}, []);
console.log(result);
Read from the Array.prototype.reduce() documentation:
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
I hope that helps!
You can reduce the array onto an object with its keys being the status property and its value an array of users with that status. Then, map over the entries to turn it back into an array of objects.
Note: The reduce function is creating a new object (accumulator) at each index. This is probably not practical for large data sets as it would be really slow.
const toSectionList = results =>
Object.entries(
results.reduce(
(obj, { user, status }) => ({
...obj,
[status]: [...(obj[status] || []), { user }],
}),
{}
)
).map(([status, data]) => ({ status, data }))
// example use:
const requiredFormat = toSectionList(mockResults)
The reduce function in this one modifies the accumulator object instead of creating a new one. It should preform better with larger data sets.
const toSectionList = results =>
Object.entries(
results.reduce((obj, { user, status }) => {
obj[status] = obj[status] || []
obj[status].push({ user })
return obj
}, {})
).map(([status, data]) => ({ status, data }))
That's what I did.
const mockResults = [
{
user: {
firstName: '1',
lastName: '1'
},
status: 'WRONG'
},
{
user: {
firstName: '2',
lastName: '2'
},
status: 'WRONG'
},
{
user: {
firstName: '3',
lastName: '3'
},
status: 'CORRECT'
}
]
function format(data) {
const resultDict = {}
for (let i of data) {
if (!resultDict[i.status]) {
resultDict[i.status] = { data: [] }
}
resultDict[i.status].data.push(i)
delete resultDict[i.status].data[resultDict[i.status].data.length - 1].status
}
const result = []
for (let i in resultDict) {
const res = {
status: i,
data: resultDict[i].data
}
result.push(res)
}
return result
}
console.log(format(mockResults))

React How to add new dynamic key to existing state?

I have getting the data from database as an array.
So now I'm getting array like this:
orders:[
{
_id:1,
name: honda,
}
{
_id:2,
name: suzuki,
}
{
_id:3,
name: audi,
}
]
So my question is how can I attach new key value to the array, so It needs to look like this:
orders:[
{
_id:1,
name: honda,
opened:true,
}
{
_id:2,
name: suzuki,
opened:true,
}
{
_id:3,
name: audi,
opened:true,
}
]
For now I'm trying with this code, but this doesn't work:
getOrders(orders).then(response => {
response.map(itm=>{
const ordersData=[...itm]
const opened={opened:true}
this.setState({
openedOrders: [ordersData,opened]
})
})
})
openedOrders is new state object that I create.
What is best solution for this?
Thanks
Your map should look like this. (Note the return statement in map function)
orders.map(item=> {
return {...item, opened:true}
})
So your function could look like
getOrders(orders).then(response => {
let openedOrders = orders.map(item=> {
return {...item, opened:true}
})
this.setState({
openedOrders
})
})
Assuming response contains the first array in your OP:
getOrders(orders).then(response => {
const openedOrders = response.map(order => ({ ...order, open: true}))
this.setState({ openedOrders } )
})
response.map(order => ({ ...order, open: true}) adds a key open with the value true to every order in the array.
To add dynamic keys to a object in javascript we use [].
var x = [{ _id : 1, name: Suzuki}];
x[0]['opened'] = true;
console.log(x);
// [{ _id : 1, name: Suzuki, opened: true}];
Use foreach() to loop through all the orders in the array and add the desired property for each order.
let orders = [{
_id: 1,
name: 'honda',
}, {
_id: 2,
name: 'suzuki',
}, {
_id: 3,
name: 'audi',
}]
orders.forEach(o => o.opened = true)
console.log(orders)
You could add a new property to the objects.
var orders = [{ _id: 1, name: 'honda' }, { _id: 2, name: 'suzuki' }, { _id: 3, name: 'audi' }],
additionalProp = { opened: true };
orders.forEach(o => Object.assign(o, additionalProp));
console.log(orders);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or map a new array without mutating the original objects.
var orders = [{ _id: 1, name: 'honda' }, { _id: 2, name: 'suzuki' }, { _id: 3, name: 'audi' }],
additionalProp = { opened: true },
result = orders.map(o => Object.assign({}, o, additionalProp));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources