Hi i am working on Angular 7 and I have 3 main arrays fetching from API like mentioned in stackblitz
And now the 3 main arrays look like this.
this.mainarr = [
{ id: 1, name: "Praveen", age: 3, color: 3 },
{ id: 2, name: "kumar", age: 2, color: 4 },
{ id: 3, name: "john", age: 4, color: 2 },
{ id: 4, name: "alex", age: 5, color: 1 },
{ id: 5, name: "profes", age: 3, color: 2 }
];
this.agearr = [
{ id: 1, age: 22 },
{ id: 2, age: 24 },
{ id: 3, age: 33 },
{ id: 4, age: 12 },
{ id: 5, age: 26 }
];
this.colorarr = [
{ id: 1, color: "black" },
{ id: 2, color: "paleblack" },
{ id: 3, color: "brown" },
{ id: 4, color: "white" },
{ id: 5, color: "greyish" }
];
So, in the mainarr i have ids and the agearr and colorarr id matched i need a different key value pair in mainarr and display that values.
so my expected result should be
[
{ id: 1, name: "Praveen", age: 3, color: 3,agename: 33,colorname: 'brown'},
{ id: 2, name: "kumar", age: 2, color: 4,agename: 24,colorname: 'white'},
{ id: 3, name: "john", age: 4, color: 2 agename: 12,colorname:'paleblack'},
{ id: 4, name: "alex", age: 5, color: 1 agename: 26,colorname:'black'},
{ id: 5, name: "profes", age: 3, color: 2 agename: 33,colorname:'paleblack'}
];
I am getting the desired result but only after page refresh how to do it any idea?TIA
Here is the updated stackblitz
In the if block you were checking for the wrong property. Corrected it.
if (this.mainarr[i].age == this.agearr[j].id)
Try like following:
getFunction() {
this.mainarr.map(x => {
x["agename"] = this.agearr.find(y => y.id == x.age)["age"];
x["colorname"] = this.colorarr.find(y => y.id == x.color)["color"];
});
console.log(this.mainarr);
}
Working Stackbllitz Example: https://stackblitz.com/edit/angular-ivy-ve5cdp?file=src/app/app.component.ts
I have the object arrays like below:
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
And what I want is to group by id, name and list out rating belonging its like below
const users = [
{
id: 1,
name: "Spider-man",
rating: {top: 1, middle: 4.5, bottom: 5}
},
{
id: 2,
name: "Iron man",
rating: {top: 3, middle: 3.5, bottom: 2}
},
{
id: 3,
name: "Hulk",
rating: {top: 5, middle: 1.5, bottom: 4}
}
];
I've tried this approach but seems it can achieve in more ways such as .reduce, for...of with more elegant, right?
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
var result = obj.top.map(x => ({
id: x.id,
name: x.name,
rating: {
top: obj.top.find(t => t.id === x.id).rating,
middle: obj.middle.find(t => t.id === x.id).rating,
bottom: obj.bottom.find(t => t.id === x.id).rating,
}
}));
console.log(result);
Any other ways to achieve it? Thanks in advance.
You need to map one of the subarrays to find each character's rating, so I think your current approach is pretty reasonable. You can make it a bit less repetitive by making an array of the properties (top, middle, bot) beforehand, then iterating over them instead of listing each different one:
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
const props = ['top', 'middle', 'bottom'];
var result = obj.top.map(x => ({
id: x.id,
name: x.name,
rating: Object.fromEntries(
props.map(prop =>
[prop, obj[prop].find(t => t.id === x.id).rating]
)
)
}));
console.log(result);
Another approach that's less computationally complex:
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
const byName = {};
for (const [prop, arr] of Object.entries(obj)) {
for (const item of arr) {
byName[item.name] ??= { ...item, rating: {} };
byName[item.name].rating[prop] = item.rating;
}
}
console.log(Object.values(byName));
You could do it in a one-liner way
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 },
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 },
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 },
],
};
const res = Array.from(
Object.entries(obj)
.flatMap(([rater, ratee]) =>
ratee.map(({ id, name, rating }) => ({
id,
name,
[rater]: rating,
}))
)
.reduce(
(acc, { id, ...restInfo }) =>
acc.set(id, { ...(acc.get(id) || {}), ...restInfo }),
new Map()
)
).map(([id, { name, ...rating }]) => ({ id, name, rating }));
console.log(res);
Using Dictionary along with Logical nullish assignment (??=)
The main idea includes 2 steps:
Loop all [key, values] of the object.
Inner each the values of the object, we loop to determine which the user's rating along with key belongs by user.id.
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
// Refactor code: using Dictionary along with `Logical nullish assignment (??=)` .
var result = Object.entries(obj).reduce((acc, [key, values]) => {
values.forEach(v => {
acc[v.id] ??= {...v, rating: {}};
acc[v.id].rating[key] = v.rating;
});
return acc;
}, {});
console.log(Object.values(result));
/* Old versions: using Array approach
var result = Object.entries(obj).reduce((acc, [key, values]) => {
values.forEach(v => {
var x = acc.find(r => r.id === v.id);
if(x !== undefined){
x.rating[key] = v.rating;
}else{
x = { id: v.id, name: v.name, rating: {[key]: v.rating} };
acc.push(x);
}
});
return acc;
}, []);
*/
More detailed explanation:
With the dictionary approach instead of array, you can achieve it with the highest performance both time and space complexity (as #CertainPerformance's comment).
From MDN Web docs said that:
The logical nullish assignment (x ??= y) operator only assigns if x is nullish (null or undefined).
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
const tempArr1 = Object.keys(obj).reduce((arr, key) => {
obj[key].forEach((item) => {
arr = [...arr, { ...item, rating: { [key]: item.rating } }];
});
return arr;
}, []);
const result = tempArr1.reduce((arr, el) => {
let tempObj = { ...el };
const index = arr.findIndex((tempItem) => tempItem.id === tempObj.id);
if (~index) {
arr[index] = {
...tempObj,
rating: {
...arr[index].rating,
...tempObj.rating
}
};
} else {
arr = [...arr, tempObj];
}
return arr;
}, []);
console.log(result);
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
var result = [];
for(let [key, values] of Object.entries(obj))
for(let item of values){
let x = result.find(r => r.id === item.id);
if(x !== undefined){
x.rating[key] = item.rating;
}else{
x = { id: item.id, name: item.name, rating: {[key]: item.rating} };
result.push(x);
}
}
console.log(result);
How do I flatten the nested Array in the Array?
Here is the example input Array,
const input = [
{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}, {
id: 4,
name: 'Charles',
otherFields: [{
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
}
]
Output Array I want to get.
[{
id: 1,
name: 'Charles'
}, {
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}, {
id: 4,
name: 'Charles'
}, {
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
I want to somehow get the output in one statement like
input.map((sth) => ({...sth??, sth.field...})); // I'm not sure :(
With flatMap you can take out the otherFields property, and returning an array containing the parent item and the other array:
const input = [{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}];
console.log(
input.flatMap(({ otherFields, ...item }) => [item, ...otherFields])
);
For more than one level, you could take a recursive approach of flattening.
const
flat = ({ otherFields = [], ...o }) => [o, ...otherFields.flatMap(flat)],
input = [{ id: 1, name: 'Charles', otherFields: [{ id: 2, name: 'Pung' }, { id: 3, name: 'James', otherFields: [{ id: 4, name: 'Jane' }] }] }],
result = input.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have a JSON list of objects with an id, name and reference to parent id :
const myList = [
{
id: 1,
name: "name1",
parentId: null
},
{
id: 5,
name: "name5",
parentId: 32
},
{
id: 32,
name: "name32",
parentId: 48
},
{
id: 48,
name: "name48",
parentId: 1
}
]
I would like to sort that list hierarchically, depending on the parent id :
[
{
id: 1,
name: "name1",
parentId: null
},
{
id: 48,
name: "name48",
parentId: 1
},
{
id: 32,
name: "name32",
parentId: 48
},
{
id: 5,
name: "name5",
parentId: 32
}
]
I'm new in Javascript programming and lodash, and I was wondering if there is an easy way to sort that list with lodash ?
Thank you in advance.
Benj
I found a solution with lodash.
Not sure it's the best but it works.
var parentId = null;
var sortedList = [];
var byParentsIdsList = _.groupBy(myList, "parentId"); // Create a new array with objects indexed by parentId
while (byParentsIdsList[parentId]) {
sortedList.push(byParentsIdsList[parentId][0]);
parentId = byParentsIdsList[parentId][0].id;
}
You can use lodash's method sortBy
var sorted = _.sortBy(myList, "parentId");
console.log(sorted);
/* OUTPUT
[
{
id: 1,
name: "name1",
parentId: null
},
{
id: 48,
name: "name48",
parentId: 1
},
{
id: 5,
name: "name5",
parentId: 32
},
{
id: 32,
name: "name32",
parentId: 48
}
]
*/
https://jsfiddle.net/L88t09ne/
with vanilla js [].sort() method:
const myList = [
{
id: 1,
name: "name1",
parentId: null
},
{
id: 5,
name: "name5",
parentId: 32
},
{
id: 32,
name: "name32",
parentId: 48
},
{
id: 48,
name: "name48",
parentId: 1
}
];
var arr = myList.sort(function(a,b){
return a.parentId -b.parentId
});
console.log(arr)
I am using kendoTreeList
and I am trying to expand all the groups. Here is my code sample
But it seems like the kendoTreeList support only expanding the first group. I tried the following selector in the expand method as well.
treeList.expand($(".k-treelist-group")); to expand all the groups. Even though the selector $(".k-treelist-group").length is 3 (total number of groups) but the treelist only expand the first group.
Any suggestion please let me know.
You are right, according with the information on their site it expands the row and not the rows.
Then you can iterate for getting the same effect:
var treeList = $("#treeList").data("kendoTreeList");
var rows = $("tr.k-treelist-group", treeList.tbody);
$.each(rows, function(idx, row) {
treeList.expand(row);
});
$(document).ready(function() {
$("#treeList").kendoTreeList({
columns: [ "id", "name" ],
loadOnDemand:false,
dataSource: [
{ id: 1, parentId: null, name: "Group", age: 30 },
{ id: 2, parentId: 1, name: "John Doe", age: 33 },
{ id: 3, parentId: 1, name: "Johson", age: 33 },
{ id: 4, parentId: null, name: "Group 2", age: 30 },
{ id: 5, parentId: 4, name: "Doe ", age: 33 },
{ id: 6, parentId: 4, name: "Noomi", age: 33 },
{ id: 7, parentId: null, name: "Group 3", age: 30 },
{ id:8, parentId: 7, name: "Doe ", age: 33 },
{ id: 9, parentId: 7, name: "Noomi", age: 33 }
]
});
var treeList = $("#treeList").data("kendoTreeList");
var rows = $("tr.k-treelist-group", treeList.tbody);
$.each(rows, function(idx, row) {
treeList.expand(row);
});
});
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1119/styles/kendo.common.min.css">
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1119/styles/kendo.default.min.css">
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.kendostatic.com/2014.3.1119/js/kendo.all.min.js"></script>
<div id="treeList"></div>
If you expand many rows you can get into some performance issues, then one alternative to looping the .expand method is to modify the data and bind it again.
var treeList = $("#treeList").data("kendoTreeList");
var dataItems = treeList.dataSource.data();
$.each(dataItems, function(i, item) {
item.expanded = true;
});
treeList.dataSource.data(dataItems);
You can also modify the data before it's bound.
dataSource: {
data: [
{ id: 1, parentId: null, name: "Group", age: 30 },
{ id: 2, parentId: 1, name: "John Doe", age: 33 },
{ id: 3, parentId: 1, name: "Johson", age: 33 },
{ id: 4, parentId: null, name: "Group 2", age: 30 },
{ id: 5, parentId: 4, name: "Doe ", age: 33 },
{ id: 6, parentId: 4, name: "Noomi", age: 33 },
{ id: 7, parentId: null, name: "Group 3", age: 30 },
{ id:8, parentId: 7, name: "Doe ", age: 33 },
{ id: 9, parentId: 7, name: "Noomi", age: 33 }
],
schema: {
parse: function(data) {
$.each(data, function(i, item) {
item.expanded = true;
});
return data;
}
}
}