This question already has answers here:
Loop through array of objects and return sum of each total values by object element id
(4 answers)
Closed 4 years ago.
I have an array called users that includes an object, which looks like this:
'user': {
'name': name,
'msg': msg
}
It is possible that in that array a user ist listed multiple times.
I would like to count the length of all his messages (msg).
This is how I tried it:
score = [];
for (i of users) {
for (s of score) {
if (s.name === i.user.name) {
score.push({
'name': i.user.name,
'counter': i.user.msg.length
});
}
else {
s.counter = s.counter + i.user.msg.length;
}
}
}
The array score which also includes an object should only include unique users. So they shouldn't be listed twice.
Anyway, that doesn't work and I am not very happy with my code, because there must be a better and an easier solution.
You can use reduce to convert scores into a map of all the unique values.
Once you have that map, if you want you can convert that into an array.
const users = [
{
name: 'user1',
msg: 'hello',
},
{
name: 'user1',
msg: 'hello2',
},
{
name: 'user2',
msg: 'world',
},
{
name: 'user2',
msg: 'world2',
},
{
name: 'user3',
msg: 'foo',
},
];
const scores = users.reduce((scores, {name, msg}) => {
if (!scores[name]) {
scores[name] = { name, counter: 0 };
}
scores[name].counter += msg.length;
return scores;
}, {});
// Now convert to an array if you want
console.log(Object.entries(scores));
You could use object instead of array for score and use user.name as key:
const score = {};
for (const user of users) {
if (score[user.name]) {
score[user.name].counter += user.msg.length;
} else {
score[user.name] = {
name: user.name,
counter: user.msg.length,
}
}
}
Related
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);
I have this array:
const chats = [
{ id: "chat-1", msg: { text: "World", date: (a date) } },
{ id: "chat-2", msg: { text: "Hello", date: (a date) } },
];
After receiving updates from my database, I receive this object:
// The second chat with update data
{ id: "chat-2", msg: { text: "Bye", date: (a date) } },
How can I (using ES6) replace the chat object from the original chats array and move it to the first index?
For now, I am doing this, but I am looking for a fastest way (smaller O)
// Get the modified chat
const modifiedChat = response.data;
// Search the modified chat in the chats array by id
const chatIndex = chats.findIndex(
(chat) => chat.id === modifiedChat.id
);
// Finally, using spread syntax, add the updated chat to the head of our current chats array
chats = [
modifiedChat,
...chats.slice(0, chatIndex),
...chats.slice(chatIndex + 1),
];
You can do the following,
const chats = [
{ id: "chat-1", msg: { text: "World", date: '' } },
{ id: "chat-2", msg: { text: "Hello", date: '' } },
];
const modifiedChat = { id: "chat-2", msg: { text: "Bye", date: '' } };
const newChats = [modifiedChat, ...chats.filter(item => item.id !== modifiedChat.id)];
console.log(newChats);
You can do something similar to how LRU cache works. You can now access every chat in O(1)
This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 2 years ago.
I have this JSON:
[
{ someTitle: 'NAME OF SomeTitle' },
[
{
id: '7oiqxhRXRqEV0D70G',
photo: 'https://co/image/ab67616d739a3e7d0c38c3af225e4695ce',
jugement: 'GOAl',
Name: 'Some Name.'
}
],
{
token: 'BQAVhYiUweHGTTlIIZHthAKzulZ-DHg'
}
]
This comes from a request I make to my node Server. If I do a console.log(req.body) I get the information above.
So when I try to do console.log(req.body.token) I get undefined.
How can I access the token property then?
The size of the JSON may change , so I can't just access it by index.
Since it is an array of objects, and the element you are looking for is at the 3th position of the array. You need to call it using index = 2 (because index starts with 0).
After that, you can access token property.
const res = [{
someTitle: 'NAME OF SomeTitle'
},
[{
id: '7oiqxhRXRqEV0D70G',
photo: 'https://co/image/ab67616d739a3e7d0c38c3af225e4695ce',
jugement: 'GOAl',
Name: 'Some Name.'
}],
{
token: 'BQAVhYiUweHGTTlIIZHthAKzulZ-DHg'
}
]
console.log(res[2].token)
Check this out
console.log(req.body[2]["token"])
If Array size is not fixed then try this
let req = {
body: [
{ someTitle: "NAME OF SomeTitle" },
[
{
id: "7oiqxhRXRqEV0D70G",
photo: "https://co/image/ab67616d739a3e7d0c38c3af225e4695ce",
jugement: "GOAl",
Name: "Some Name.",
},
],
{
token: "BQAVhYiUweHGTTlIIZHthAKzulZ-DHg",
},
],
};
let data = req.body;
let token = "";
for (let each of data) {
if (each.hasOwnProperty("token")) {
token = each["token"];
break;
}
}
console.log(token)
I have an array with a few objects which I'm trying to combine into one single object
[
{ user: { '563D': { pId: '12', seasion: '120', value: true } } },
{ user: { '563D': { pId: '11', seasion: '120', value: false } } },
...
]
pId is unique
seasion is the same for each object (almost never changing)
value can be anything
I want to have something like this:
{
id: '563D',
seasion: '120',
types: {
12: // pId
{
value: true
},
11:
{
value: false
}
}
}
I tried to use reduce and forEach but I wasnt been able to achieve my goals
due to poor understanding of those 2 methods.
EDIT:
forgot about several users input, sorry
[
{
users: {
'563D': [Object],
'4b07': [Object]
}
},
{
users: {
'563D': [Object],
'4b07': [Object]
}
},
{
users: {
'563D': [Object],
'4b07': [Object]
}
}
]
You could use reduce and destructuring to group the objects based on the first key inside user. Then use Object.values() to get the array of each group values:
Get user from each object by destructuring the parameter
Destructure the first entry of the user to get the key (like '563D') and the nested properties separately)
Use the || operator to check if the accumulator already has the id as it's property. If yes, use it. Else assign a new value with { id, seasion, types: {} }. This is using the Shorthand property names.
Update the types with pId as key and { value } as it's value
const input = [{user:{'563D':{pId:'12',seasion:120,value:true}, '4b07':{pId:'12',seasion:120,value:true}}},{user:{'563D':{pId:'11',seasion:120,value:false},'4b07':{pId:'11',seasion:120,value:false}}}]
const output = input.reduce((r, { user }) => {
for(const [id, { pId, seasion, value }] of Object.entries(user)) {
r[id] = r[id] || { id, seasion, types: {} };
r[id].types[pId] = { value };
}
return r;
}, {})
console.log(Object.values(output))
If you have only one unique id in the array, you can simplify the reduce to:
const input = [{user:{'563D':{pId:'12',seasion:120,value:true}}},{user:{'563D':{pId:'11',seasion:120,value:false}}}]
const output = input.reduce((r, { user }) => {
const [id, { pId, seasion, value }] = Object.entries(user)[0];
return { id, seasion, types: { ...r.types, [pId]: { value } } }
}, {})
console.log(output)
I have 2 arrays array1, array2.
array 1 objects: userName, userId
array 2 objects: userId, msg
i want to get array3: userId, userName, msg
Array1:
[{ userName: 'vimal', userId: 789 },
{ userName: 'kabilan', userId: 456 },
{ userName: 'yathavan', userId: 123 }]
Array2:
[ { userId: '123', msg: 'hi' },
{ userId: '789', msg: 'yth' },
{ userId: '789', msg: 'hu' } ]
i want to compare 2 arrays and get output like this.
Array3:
[ { userId: '123', userName: 'yathavan', msg: 'hi' },
{ userId: '789', userName: 'vimal', msg: 'yth' },
{ userId: '789', userName: 'vimal', msg: 'hu' } ]
An off-the-shelf, "functional programming" approach:
var users = [{ userName: 'vimal', userId: 789 },
{ userName: 'kabilan', userId: 456 },
{ userName: 'yathavan', userId: 123 }]
var messages = [ { userId: '123', msg: 'hi' },
{ userId: '789', msg: 'yth' },
{ userId: '789', msg: 'hu' } ]
var user_message_list = [];
messages.map(function (message) {
return users.
filter(function (user) {
return user.userId == message.userId
}).
map(function (user) {
return {
"userId": user.userId,
"userName": user.userName,
"msg": message.msg
}
})
})
.forEach(function (item) { // eliminate nested layers
user_message_list.push.apply(user_message_list, item)
})
JSFiddle Functional
Explanation:
Two arrays of objects, one a list of users, and the other a list of messages by some of those users.
You're wanting to flesh out a report of the messages showing the usernames, so start with the messages array and loop through it. Now, for each message loop through the users list and retrieve the corresponding username.
The "loopy" approach is like this:
var messages_users = []
var message_user = {}
for (ii=0; ii < messages.length; ii++) {
message_user = {
"userId": messages[ii].userId,
"msg": messages[ii].msg
}
for (iii=0; iii < users.length; iii++) {
if ( messages[ii].userId == users[iii].userId ) {
message_user.userName = users[iii].userName
}
}
messages_users.push(message_user)
}
JSFiddle Loopy
Alternatively, using Functional Programming concepts, start by maping a function to each item in the messages array. That function takes the users array and filters it to find the corresponding user object for the current message, and map on that result to combine the current message information with the filtered user result. At this point you have an object wrapped in an array, since the map and filter methods return arrays. Therefore, the final operation is to loop using the forEach method to remove the extra array layer. Some JavaScript libraries have a concatAll or better yet concatMap method that hides that extra loop. In that case you'd have something like this:
var user_message_list = messages.
concatMap(function (message) {
return users.
filter(function (user) {
return user.userId == message.userId
}).
map(function (user) {
return {
"userId": user.userId,
"userName": user.userName,
"msg": message.msg
}
})
})
The benefit here is tighter coupling between the language nomenclature and the procedural concepts. For example: filter(... vs. for (i=0; ... if ( arr[i] ===.... Both constructs loop and select items based on criteria, hence filter.
More on Functional Programming in JavaScript
I'd make a users array indexed my the userid that contains the username;
var users = [];
for(var i=0; i<arr1.length; i++)
users[arr1[i].userId] = arr1[i].userName;
now make your output array, and go through the 2nd array. using the users array to insert;
var arr3 = [];
for(var i=0; i<arr2.length; i++)
arr3.push({userId:arr2[i].userId, userName:users[arr2[i].userId], msg:arr2[i].msg});
You would do something like this, if userId value was not a String in ary2:
var ary1 =[{userName:'vimal', userId:789}, {userName:'kabilan', userId:456}, {userName:'yathavan', userId:123}];
var ary2 = [{userId:123, msg:'hi'}, {userId:789, msg:'yth'}, {userId:789, msg:'hu'}];
function specialMerge(ar1, ar2){
var r = [];
for(var i=0,l=ar1.length; i<l; i++){
var p = ar1[i];
for(var n=0,c=ar2.length; n<c; n++){
var m = ar2[n];
if(p.userId === m.userId){
r.push({userId:p.userId, userName:p.userName, msg:m.msg});
}
}
}
return r;
}
var resultArrayOfObjects = specialMerge(ary1, ary2);