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

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"

Related

Sort a nested array, given its inner value, based on another array

I have 2 arrays, one (array1) which needs to be sorted based on its inner key, role, according to another (array2). I have tried different solutions but cannot progress any further since i don't understand what steps i should take
I have the following output: Array1
{
"id":12,
"roles":[
{
"id":12,
"role":"team_player",
"sub_role":null,
"team_meta":{
"default_player_role":{
"pos":null,
"role":"LWB"
}
}
}
],
"user_email":"w#w.w"
},
{
"id":1575,
"roles":[
{
"id":1672,
"role":"team_player",
"sub_role":null,
"team_meta":{
"default_player_role":{
"pos":null,
"role":"LB"
}
}
}
],
"user_email":"j#j.s"
},
{
"id":1576,
"roles":[
{
"id":1673,
"role":"team_player",
"sub_role":null,
"team_meta":{
"default_player_role":{
"pos":null,
"role":"CAM"
}
}
}
],
"user_email":"E#E.E",
},
And i want to order the array above according to the order of this:
const array2 = ["LWB", "LB", "CAM"]
The issue i'm having is that the given key that the sorting should be according to in array1 is too deep, and I haven't found any way to map the "role" from the first array with the array2.
You need to get role and with this value get the index for the order.
const
getRole = ({ roles: [{ team_meta: { default_player_role: { role } }}] }) => role,
data = [{ id: 1576, roles: [{ id: 1673, role: "team_player", sub_role: null, team_meta: { default_player_role: { pos: null, role: "CAM" } } }], user_email: "E#E.E" }, { id: 12, roles: [{ id: 12, role: "team_player", sub_role: null, team_meta: { default_player_role: { pos: null, role: "LWB" } } }], user_email: "w#w.w" }, { id: 1575, roles: [{ id: 1672, role: "team_player", sub_role: null, team_meta: { default_player_role: { pos: null, role: "LB" } } }], user_email: "j#j.s" }],
order = ["LWB", "LB", "CAM"];
data.sort((a, b) => order.indexOf(getRole(a)) - order.indexOf(getRole(b)));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Over several loops you can also sort it but probably not an elegant solution:
const nestedArray = [...]; // Replace Array
const sortByArray = ["LWB", "LB", "CAM"];
const sortedArray = [];
sortByArray.forEach(function(sortByArrayValue) {
nestedArray.forEach(function(nestedArrayValue) {
nestedArrayValue.roles.forEach(function(role) {
if (role.team_meta.default_player_role.role === sortByArrayValue) {
sortedArray.push(nestedArrayValue);
}
});
});
});

How to sort an array of objects by comparing different fields in typescript

So I found examples on how to sort arrays by comparing the same field, but I need to sort them by comparing different fields. For example I have a lists of objects where each object has a field for their name and parent. I want to sort the list so that the people appear next to their parent. Example:
[
{
"name": "Bob",
"parent": "Linda"
},
{
"name": "Charlie",
"parent": "Gregory"
},
{
"name": "Linda",
"parent": "Stacy"
},
{
"name": "Andrew",
"parent": "Gabriel"
},
{
"name": "Gregory",
"parent": "Thomas"
}
]
After sorting I want Bob to be next to Linda and Charlie to be next to Gregory.
Hello #poppo8989: Welcome to Stack Overflow.
Suggestion: If you have control over the data presented in your question, you might consider storing it in a structure that better represents the relationships.
Otherwise, here's a take on solving your problem:
Explore code in TypeScript Playground
type Person = {
name: string;
parent: string;
};
type RelationshipData = {
child?: Person;
parent?: Person;
};
function getRelationships (people: Person[], person: Person): RelationshipData {
return {
child: people.find(p => p.parent === person.name),
parent: people.find(p => p.name === person.parent),
};
}
function getSortedPeople (people: Person[]): Person[] {
const sorted: Person[] = [];
const copy = [...people];
while (copy.length > 0) {
let person: Person | undefined = copy[0];
let done = false;
// set person to furthest ancestor
while (person && !done) {
const {parent} = getRelationships(copy, person);
if (parent) person = parent;
else done = true;
}
// remove from copy array and add to sorted array, repeatedly for each child
while (person) {
copy.splice(copy.indexOf(person), 1);
sorted.push(person);
person = getRelationships(copy, person).child;
}
}
return sorted;
}
function main () {
const people: Person[] = [
{name: 'Bob', parent: 'Linda'},
{name: 'Charlie', parent: 'Gregory'},
{name: 'Linda', parent: 'Stacy'},
{name: 'Andrew', parent: 'Gabriel'},
{name: 'Gregory', parent: 'Thomas'},
];
const sorted = getSortedPeople(people);
console.log(sorted); //=> Linda, Bob, Gregory, Charlie, Andrew
}
main();

Dynamically parsing JSON arrays in JavaScript

I'm trying to parse a JSON file stored locally on my machine in JavaScript in discord.js (v12). This JSON has several keys and values:
{
"name": "Robert",
"rank": "Owner",
"hobbies": [{
"id": 1,
"name": "gaming"
}, {
"id": 2,
"name": "listening to music"
}, {
"id": 3,
"name": "vibing"
}, {
"id": 4,
"name": "driving down the highway"
}],
"roles": [{
"id": 1,
"name": "Founder"
}, {
"id": 2,
"name": "Premium Member"
}]
}
I want to send the above in a message on Discord as follows:
name: Robert
rank: Owner
hobbies: gaming, listening to music, vibing, driving down the highway
roles: Founder, Premium Member
I also want this to be dynamic. Meaning my code should adapt if a new key and value is added to the current set.
With the current code used, this is my result:
name: Robert
rank: Owner
hobbies: gaming, listening to music, vibing, driving down the highway
This is my current code:
let noted = ``
var raw = fs.readFileSync(name)
var obj = JSON.parse(raw)
for (var item in obj) {
if (obj[item] instanceof Object) {
for (var i in obj.hobbies) {
noted += `${obj.hobbies[i].name}, `
}
} else {
noted += `${item}: ${obj[item]}\n`
noted += `hobbies: `
}
}
message.channel.send(noted)
The variable name is const name = require("./names.json"); at the top of the code.
This code works fine with name, rank and hobbies.
roles has to be manually checked in the for loop if I want it to be visible. My goal is to cause any new keys to be added to be automatically detected and added into the noted variable.
I've seen something similar done using map(), but I tried it without getting anywhere good. This is rather sloppy code as well but I'm not interested in keeping it clean.
You could do something like this with map and join:
const obj = {"name":"Robert","rank":"Owner","hobbies":[{"id":1,"name":"gaming"},{"id":2,"name":"listening to music"},{"id":3,"name":"vibing"},{"id":4,"name":"driving down the highway"}],"roles":[{"id":1,"name":"Founder"},{"id":2,"name":"Premium Member"}]};
const noted = Object.entries(obj)
.map(([key, val]) =>
`${key}: ${
val instanceof Array ? val.map(x => x.name).join(', ') : val
}`)
.join('\n');
console.log(noted);
Here is an iterative solution using object-scan.
I find it a bit easier to read, but most importantly it is very flexible as to which keys you want to traverse.
// const objectScan = require('object-scan');
const myData = { name: 'Robert', rank: 'Owner', hobbies: [{ id: 1, name: 'gaming' }, { id: 2, name: 'listening to music' }, { id: 3, name: 'vibing' }, { id: 4, name: 'driving down the highway' }], roles: [{ id: 1, name: 'Founder' }, { id: 2, name: 'Premium Member' }] };
const convert = (data) => {
const r = objectScan(['*', '*[*].name'], {
reverse: false,
filterFn: ({ isLeaf, context, key, value }) => {
if (isLeaf) {
if (!(key[0] in context)) {
context[key[0]] = value;
} else {
context[key[0]] += `, ${value}`;
}
}
}
})(data, {});
return Object.entries(r).map(([k, v]) => `${k}: ${v}`).join('\n');
};
console.log(convert(myData));
/* =>
name: Robert
rank: Owner
hobbies: gaming, listening to music, vibing, driving down the highway
roles: Founder, Premium Member
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan

JavaScript (ReactJS) comparing two Objects

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)
);

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