Circular Referenced Objects Javascript - javascript

Having issues with this exercise:
// Let’s say we have an array of artists and we want to create a map-like object of their instruments.
const artists = [
{
id: '1',
name: 'Jimi Hendrix',
instrument: {
id: '1',
name: 'Guitar',
color: 'wood',
}
},
{
id: '2',
name: 'Jimmy Page',
instrument: {
id: '1',
name: 'Guitar',
color: 'wood',
}
},
{
id: '3',
name: 'Krist Novoselic',
instrument: {
id: '2',
name: 'Bass',
color: 'black',
}
},
{
id: '4',
name: 'Emmanuelle Proulx',
},
{
id: '5',
name: 'Jimmy Chamberlin',
instrument: {
id: '3',
name: 'Drums'
}
},
];
/* Expected results */
/* {
1: {
name: 'Guitar',
color: 'wood',
},
...
} */
const result = [];
artists.map((item) => {if ((item.instrument !== undefined)) {result.push(item.instrument.id = item.instrument)}});
So far I've extracted th instruments without undefined, but the ids are reference to ids and cannot get to extract the number id or to build it with the proper structure because of the circular reference.

So to use the map you'd still get undefined values. You probably would want to use reduce and do the following.
const artists = [
{
id: "1",
name: "Jimi Hendrix",
instrument: {
id: "1",
name: "Guitar",
color: "wood",
},
},
{
id: "2",
name: "Jimmy Page",
instrument: {
id: "1",
name: "Guitar",
color: "wood",
},
},
{
id: "3",
name: "Krist Novoselic",
instrument: {
id: "2",
name: "Bass",
color: "black",
},
},
{
id: "4",
name: "Emmanuelle Proulx",
},
{
id: "5",
name: "Jimmy Chamberlin",
instrument: {
id: "3",
name: "Drums",
},
},
];
const instruments = artists.reduce((acc, artist) => {
if (!artist.instrument) return acc;
const { id, name, color } = artist.instrument;
acc[id] = { name, color };
return acc;
}, {});
console.log(instruments);

try this
const instruments = artists.reduce((acc, artist) => {
if (!artist.instrument) return acc;
acc[artist.instrument.id] = {
name: artist.instrument.name,
color: artist.instrument.color
};
return acc;
}, {});
result
{
"1": {
"name": "Guitar",
"color": "wood"
},
"2": {
"name": "Bass",
"color": "black"
},
"3": {
"name": "Drums"
}
}

Related

How to compare two array of objects and return the not matching object?

obj1 is the original object and obj2 is the changed object. I want to get the key , value pair and the type of all the changed object inside obje2 array of objects.
So, I need something like this where if "name" or "id" value is different in obj2 return the object along with the type.
changedObj = [
{
type:"mobile",
name:"Temple Runs",
id:2259
},
{
type:"pc",
name:"Pubgs",
id:222
}
]
obj1 = [
{
type: "mobile",
games: [
{
name: "Temple Run",
id: 2259,
},
{
name: "Subway Surfer",
id: 2271,
},
{
name: "Pubg",
id: 2272,
},
],
},
{
type: "pc",
games: [
{
name: "Pubg",
id: 222,
},
{
name: "Fortnite",
id: 2274,
},
{
name: "Nfs",
id: 2272,
},
],
},
];
obj2 = [
{
type: "mobile",
games: [
{
name: "Temple Runs",
id: 2259,
},
{
name: "Subway Surfer",
id: 2271,
},
{
name: "Pubg",
id: 2272,
},
],
},
{
type: "pc",
games: [
{
name: "Pubgs",
id: 222,
},
{
name: "Fortnite",
id: 2274,
},
{
name: "Nfs",
id: 2272,
},
],
},
];
How to achieve something like this ?
In order to find the difference, you will need to:
Map all of the updated platforms (type and games)
Filter the updated games and locate the original game by ID
Flat-map the games in each platform and include the type
const main = () => {
const delta = diff(changed, data);
console.log(delta);
};
const diff = (updated, original) =>
updated
.map(({ type, games }) => ({
type,
games: games
.filter(({ name, id }) => original
.find(platform => platform.type === type).games
.find(game => game.id === id)?.name !== name)
}))
.flatMap(({ type, games }) =>
games.map(({ name, id }) =>
({ name, id, type })));
const data = [{
type: "mobile",
games: [
{ name: "Temple Run", id: 2259 },
{ name: "Subway Surfer", id: 2271 },
{ name: "Pubg", id: 2272 }
],
}, {
type: "pc",
games: [
{ name: "Pubg", id: 222 },
{ name: "Fortnite", id: 2274 },
{ name: "Nfs", id: 2272 }
]
}];
const changed = [{
type: "mobile",
games: [
{ name: "Temple Runs", id: 2259 },
{ name: "Subway Surfer", id: 2271 },
{ name: "Pubg", id: 2272 }
],
}, {
type: "pc",
games: [
{ name: "Pubgs", id: 222 },
{ name: "Fortnite", id: 2274 },
{ name: "Nfs", id: 2272 }
]
}];
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }

Remove/Add all childrenNode of a tree from an array when clicking on a parentNode

I have this nested object :
export interface RenderTree {
id: string;
name: string;
children?: readonly RenderTree[];
}
export const UserLoginRoleV2Tree: RenderTree = {
id: "root",
name: "APP",
children: [
{
id: "1",
name: UserLoginRoleV2.DASHBOARD
},
{
id: "2",
name: UserLoginRoleV2.REPORTING,
children: [
{
id: "2.1",
name: UserLoginRoleV2.REPORTS
},
{
id: "2.2",
name: UserLoginRoleV2.SALES_DETAILS
},
{
id: "2.3",
name: UserLoginRoleV2.LEADS_DETAILS
}
]
},
{
id: "3",
name: UserLoginRoleV2.SALES_DATA,
children: [
{
id: "3.1",
name: UserLoginRoleV2.SALES
},
{
id: "3.2",
name: UserLoginRoleV2.LEADS
},
{
id: "3.3",
name: UserLoginRoleV2.CALLS
},
{
id: "3.4",
name: UserLoginRoleV2.PHONE_CLOSING
}
]
},
{
id: "4",
name: UserLoginRoleV2.TRACKING,
children: [
{
id: "4.1",
name: UserLoginRoleV2.UNIVERSAL_SCRIPT
},
{
id: "4.2",
name: UserLoginRoleV2.SOURCE_LINKS
},
{
id: "4.3",
name: UserLoginRoleV2.URL_RULES
},
{
id: "4.4",
name: UserLoginRoleV2.PRODUCTS
},
{
id: "4.4",
name: UserLoginRoleV2.TAGS
}
]
},
{
id: "5",
name: UserLoginRoleV2.SETTINGS,
children: [
{
id: "5.1",
name: UserLoginRoleV2.PROFILE
},
{
id: "5.2",
name: UserLoginRoleV2.BILLING
},
{
id: "5.3",
name: UserLoginRoleV2.SUB_USERS
},
{
id: "5.4",
name: UserLoginRoleV2.CONNECTED_ACCOUNTS
},
{
id: "5.5",
name: UserLoginRoleV2.INTEGRATIONS
},
{
id: "5.6",
name: UserLoginRoleV2.TRACKING_SETTINGS
},
{
id: "5.7",
name: UserLoginRoleV2.TRACKING_DOMAINS
}
]
}
]
}
From this object, I'm able to build a Tree. Each node of the tree has a checkbox. To know if the checkbox is checked or not, I have a state array when I keep all nodes that are checked :
interface State {
roles: Array<string>;
}
<TreeItem key={nodes.id} nodeId={nodes.id} label={<Checkbox checked={this.state.roles.includes(nodes.name)} onClick={...}>
{Array.isArray(nodes.children)
? nodes.children.map((node) => this.renderTree(node))
: null}
</TreeItem>
I'm looking for a way to remove all children of a node from the array when clicking on it, knowing that a child can have children too.
I feel that we could make it with a recursive function, but I don't have success with that for now. Can you help me?
Okay I resolved it with Depth-first search
/**
* Get all children of a node.
* #param branch The node whose children you want to know
* #param callback Function to apply on each node.
*/
const breadthFirstSearch = (branch: TreeBranch): TreeBranch[] => {
let queue = new Array(branch);
let explored = new Array(branch);
let res = new Array();
let b: TreeBranch;
while (queue.length !== 0) {
b = queue.shift();
res.push(b);
b.children?.forEach(child => {
if (!explored.includes(child)) {
queue.push(child);
explored.push(child);
}
})
}
return res;
}

Please help to Convert Array to Object

I need to convert an array with only ids and an object with Id & Name need to find object array element from the object and create new Object
App.js:
["111","114","117']
Object:
[
{ id: "111", Name: "Jerry" },
{ id: "112", Name: "Tom" },
{ id: "113", Name: "Mouse" },
{ id: "114", Name: "Minny" },
{ id: "115", Name: "Mayavi" },
{ id: "116", Name: "Kuttoosan" },
{ id: "117", Name: "Raju" }
];
Result Need:
[
{ id: "111", Name: "Jerry" },
{ id: "114", Name: "Minny" },
{ id: "117", Name: "Raju" }
];
const array = ["111", "114", "117"];
const object = [
{ id: "111", Name: "Jerry" },
{ id: "112", Name: "Tom" },
{ id: "113", Name: "Mouse" },
{ id: "114", Name: "Minny" },
{ id: "115", Name: "Mayavi" },
{ id: "116", Name: "Kuttoosan" },
{ id: "117", Name: "Raju" }
];
const result = object.filter(o => array.includes(o.id));
This should give you the result you want, pay attention that what you called object actually is an array of objects, as far as i understood you want keep only the object with an id contained in the first array, so as i shown just filter them
I think you can just use .filter() to achieve the same result.
const targetIds = ["111","114","117"];
const nameObjects = [{id:"111", Name:"Jerry"}, {id:"112", Name:"Tom"}, {id:"113", Name:"Mouse"}, {id:"114", Name:"Minny"}, {id:"115", Name:"Mayavi"}, {id:"116", Name:"Kuttoosan"}, {id:"117", Name:"Raju"}];
const filtered = nameObjects.filter((obj) => targetIds.indexOf(obj.id) !== -1);
// Which should give the result you need
// [{id:"111", Name:"Jerry"}, {id:"114", Name:"Minny"},{id:"117", Name:"Raju"}]
Use the .filter() to get the result
const ids = ["111", "114", "117"];
const nameids = [
{ id: "111", Name: "Jerry" },
{ id: "112", Name: "Tom" },
{ id: "113", Name: "Mouse" },
{ id: "114", Name: "Minny" },
{ id: "115", Name: "Mayavi" },
{ id: "116", Name: "Kuttoosan" },
{ id: "117", Name: "Raju" }
];
const result = nameids.filter(res => ids.includes(res.id));
console.log(result);

JavaScript - transform object, consolidate

I'm trying to transform the object below. I need to create a new array of unique locations, with the location and item objects in each node.
With the help of JackOfAshes I was able to get halfway there in this PEN
Transform this:
const orig = [
{
item: {
name: "cat",
id: "ca_123"
},
location: {
name: "porch",
id: "por_123"
}
},
{
item: {
name: "dog",
id: "do_123"
},
location: {
name: "porch",
id: "por_123"
}
},
{
item: {
name: "snake",
id: "sn_123"
},
location: {
name: "forest",
id: "for_123"
}
},
{
item: {
name: "bird",
id: "bi_123"
},
location: {
name: "forest",
id: "for_123"
}
},
{
item: {
name: "beer",
id: "be_123"
},
location: {
name: "fridge",
id: "fri_123"
}
}
];
Into this:
const desired = [
{
name: "porch",
id: "por_123",
items: [
{
name: "cat",
id: "ca_123"
},
{
name: "dog",
id: "do_123"
}
]
},
{
name: "forest",
id: "for_123",
items: [
{
name: "snake",
id: "sn_123"
},
{
name: "bird",
id: "bi_123"
}
]
},
{
name: "fridge",
id: "fri_123",
items: [
{
name: "beer",
id: "be_123"
}
]
}
];
You can do it, or use reduce
const orig = [
{
item: {
name: "cat",
id: "ca_123"
},
location: {
name: "porch",
id: "por_123"
}
},
{
item: {
name: "dog",
id: "do_123"
},
location: {
name: "porch",
id: "por_123"
}
},
{
item: {
name: "snake",
id: "sn_123"
},
location: {
name: "forest",
id: "for_123"
}
},
{
item: {
name: "bird",
id: "bi_123"
},
location: {
name: "forest",
id: "for_123"
}
},
{
item: {
name: "beer",
id: "be_123"
},
location: {
name: "fridge",
id: "fri_123"
}
}
];
let formattedData = {}
orig.forEach(data=>{
if(!formattedData[data.location.id]) formattedData[data.location.id]= {
id: data.location.id,
name: data.location.name,
items:[]
}
formattedData[data.location.id].items.push(data.item)
})
const finalResponse = Object.entries(formattedData).map((e) => ( { ...e[1] } ));
console.log(finalResponse)

Group by array of objects by a nested key

I have the following data:
const data = [
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "Italy"
},
score: 5
},
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "France"
},
score: 4.5
},
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "UK"
},
score: 4.9
},
{
parent: {
id: "2",
name: "Afrique"
},
item: {
name: "Morocco"
},
score: 3.1
},
{
parent: {
id: "2",
name: "Afrique"
},
item: {
name: "Egypt"
},
score: 3.9
}
];
I want to group it based on the parent.id and calculate the average score, so I can have the following result:
[
{
parent: {
id: "1",
name: "Europe",
items: [
{
name: "Italy"
},
{
name: "France"
},
{
name: "UK"
}
],
score: 4.8
}
},
{
parent: {
id: "2",
name: "Afrique",
items: [
{
name: "Morocco"
},
{
name: "Egypt"
}
],
score: 3.5
}
}
]
I used the following function, but it doesn't work for the nested key, and also it's doesn't return the desired result schema.
let group = cars.reduce((r, a) => {
console.log("a", a);
console.log('r', r);
r[a.make] = [...r[a.parent.id] || [], a];
return r;
}, {});
console.log("group", group);
You can use _reduce() function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
var result = data.reduce((res, data) => {
if(!res[data.parent.id]) {
data.item = [data.item];
res[data.parent.id] = data;
} else {
res[data.parent.id]['item'].push(data['item']);
res[data.parent.id]['score'] = (res[data.parent.id]['score'] + data['score'])/2;
}
return res;
}, [])
.filter(x => x != null)
const data = [
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "Italy"
},
score: 5
},
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "France"
},
score: 4.5
},
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "UK"
},
score: 4.9
},
{
parent: {
id: "2",
name: "Afrique"
},
item: {
name: "Morocco"
},
score: 3.1
},
{
parent: {
id: "2",
name: "Afrique"
},
item: {
name: "Egypt"
},
score: 3.9
}
];
var result = data.reduce((res, data) => {
if(!res[data.parent.id]) {
data.item = [data.item];
res[data.parent.id] = data;
} else {
res[data.parent.id]['item'].push(data['item']);
res[data.parent.id]['score'] = (res[data.parent.id]['score'] + data['score'])/2;
}
return res;
}, [])
.filter(x => x != null)
console.log(result)
Create an object/hashmap, then format the resulting object into an array.
let continents = {}
data.forEach(function(country){
const continent_id = country.parent.id
let continent = continents[continent_id]
if(!continent){
continent = {
id: continent_id,
name: country.parent.name,
items: [],
}
continents[continent_id] = continent
}
continent.items.push({
name: country.item.name,
score: country.score
})
})
continents = Object.entries(continents).map(item => ({parent: item[1]}))
console.log(continents)
Output:
[
{
"parent":{
"id":"1",
"name":"Europe",
"items":[
{
"name":"Italy",
"score":5
},
{
"name":"France",
"score":4.5
},
{
"name":"UK",
"score":4.9
}
]
}
},
{
"parent":{
"id":"2",
"name":"Afrique",
"items":[
{
"name":"Morocco",
"score":3.1
},
{
"name":"Egypt",
"score":3.9
}
]
}
}
]
From the data you've provided if you additionaly need to count average of score property, use the following reduce method: it will iterate trough your data, group it and calculate total score value and count of score values. And after reduce groups object perform map that will calculate average for score for all the groups using totalScore and scoreCount
const data = [
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "Italy"
},
score: 5
},
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "France"
},
score: 4.5
},
{
parent: {
id: "1",
name: "Europe"
},
item: {
name: "UK"
},
score: 4.9
},
{
parent: {
id: "2",
name: "Afrique"
},
item: {
name: "Morocco"
},
score: 3.1
},
{
parent: {
id: "2",
name: "Afrique"
},
item: {
name: "Egypt"
},
score: 3.9
}
];
let group = data.reduce((acc, rec) => {
if (acc.find(item => item.parent.id === rec.parent.id))
{
const idx = acc.findIndex(item => item.parent.id === rec.parent.id)
acc[idx].parent.items = acc[idx].parent.items.concat(rec.item)
acc[idx].parent.score += rec.score
acc[idx].parent.scoreCount +=1
} else {
acc = acc.concat({parent: {...rec.parent, score: rec.score, items: [rec.item], scoreCount:1}})
}
return acc
}, []).map(it => ({parent: {id: it.parent.id, name:it.parent.name, score: (it.parent.score / it.parent.scoreCount), items: it.parent.items}}));
console.log("group", group);

Categories