I have a json array after the form submission using formSerialize function like this
[
{"name":"client_management-testmonitoring","value":"0"},
{"name":"client_operations-testmonitoring","value":"0"},
{"name":"tpl_management-testmonitoring","value":"0"},
{"name":"tpl_operations-testmonitoring","value":"0"},
{"name":"channel_partner-testmonitoring","value":"0"},
{"name":"operator-testmonitoring","value":"0"},
{"name":"financier-testmonitoring","value":"0"},
{"name":"client_management-test_monitoring_2","value":"0"},
{"name":"client_operations-test_monitoring_2","value":"0"},
{"name":"tpl_management-test_monitoring_2","value":"0"},
{"name":"tpl_operations-test_monitoring_2","value":"0"},
{"name":"channel_partner-test_monitoring_2","value":"0"},
{"name":"operator-test_monitoring_2","value":"0"},
{"name":"financier-test_monitoring_2","value":"0"},
{"name":"client_management-test_monitoring_3","value":"0"},
{"name":"client_operations-test_monitoring_3","value":"0"},
{"name":"tpl_management-test_monitoring_3","value":"0"},
{"name":"tpl_operations-test_monitoring_3","value":"0"},
{"name":"channel_partner-test_monitoring_3","value":"0"},
{"name":"operator-test_monitoring_3","value":"0"},
{"name":"financier-test_monitoring_3","value":"0"}
]
and i need to convert this array like this :
[
{
"role": [
{
"role_name": "client_management",
"report_name": [
{
"test_monitoring_1": 1,
"test_monitoring_2": 1,
"test_monitoring_3": 0
}
]
}
]
},
{
"role": [
{
"role_name": "financier",
"report_name": [
{
"test_monitoring_1": 1,
"test_monitoring_2": 0,
"test_monitoring_3": 1
}
]
}
]
}
]
am trying this code to get the multidimesional array.
var formData = $('#' + reportType).serializeArray(),matrix_array =[];
for (var u = 0; u < formData.length; u++) {
for (var user in formData[u])
{
if (user == 'name') {
var matrix_name_n = formData[u][user],
matrix_name_a = matrix_name_n.split('-'),
role_name = matrix_name_a[0],
parameter_name = matrix_name_a[1];
var matrix_array_2 = [];
}
if (user == 'value') {
var matrix_param_value = formData[u][user], matrix_array_3 = [matrix_param_value];
}
}
var matrix_array2 = {};
var matrix_array2 = {};
matrix_array2["role"] = role_name;
matrix_array2[parameter_name] = matrix_param_value;
matrix_array_2.push(matrix_array2);
matrix_array.push(matrix_array_2);
var insert_matrix = {};
insert_matrix = JSON.stringify(formData);
}
but am not getting the expected result.Please help someone to sort out this issue
You could split the name by minus sign and use the first part as role_name and the second part as report_name property of the inner object.
var data = [{ name: "client_management-testmonitoring", value: 0 }, { name: "client_operations-testmonitoring", value: 0 }, { name: "tpl_management-testmonitoring", value: 0 }, { name: "tpl_operations-testmonitoring", value: 0 }, { name: "channel_partner-testmonitoring", value: 0 }, { name: "operator-testmonitoring", value: 0 }, { name: "financier-testmonitoring", value: 0 }, { name: "client_management-test_monitoring_2", value: 0 }, { name: "client_operations-test_monitoring_2", value: 0 }, { name: "tpl_management-test_monitoring_2", value: 0 }, { name: "tpl_operations-test_monitoring_2", value: 0 }, { name: "channel_partner-test_monitoring_2", value: 0 }, { name: "operator-test_monitoring_2", value: 0 }, { name: "financier-test_monitoring_2", value: 0 }, { name: "client_management-test_monitoring_3", value: 0 }, { name: "client_operations-test_monitoring_3", value: 0 }, { name: "tpl_management-test_monitoring_3", value: 0 }, { name: "tpl_operations-test_monitoring_3", value: 0 }, { name: "channel_partner-test_monitoring_3", value: 0 }, { name: "operator-test_monitoring_3", value: 0 }, { name: "financier-test_monitoring_3", value: 0 }],
result = data.reduce(function (hash) {
return function (r, a) {
var parts = a.name.split('-');
if (!hash[parts[0]]) {
hash[parts[0]] = {};
r[0].role.push({ role_name: parts[0], report_name: [hash[parts[0]]] });
}
if (!parts[1].match(/\d$/)) {
parts[1] = 'test_monitoring_1';
}
hash[parts[0]][parts[1]] = a.value;
return r;
}
}(Object.create(null)), [{ report_name: "monitoring", role: [] }]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
i have two array of objects like below, am trying to compare two arrays and looking to update the object total value of arr1 if the id matches with arr2.
const arr1 = [
{
id: 1,
value: { total: 0 },
},
{
id: 2,
value: { total: 0 },
},
{
id: 3,
value: { total: 0 },
},
id: 4,
value: { total: 0 },
},
];
const arr2 = [
{
id: 2,
value: 3 ,
},
{
id: 3,
value: 5,
},
];
I am trying to compare two arrays and looking to update the object total value of arr1 if the id matches with arr2
expected result is
const arr1 = [
{
id: 1,
value: { total: 0 },
},
{
id: 2,
value: { total: 3 },
},
{
id: 3,
value: { total: 5 },
},
{
id: 4,
value: { total: 0 },
},
];
I have tried the below code,
arr1.map((item) => {
arr2.find((element) => {
if (element.id === item.id ) {
item = {
...item,
value: {
...item.value,
total: item.value.total + element.value,
},
};
console.log(item);
}
});
return item;
});
I have changed the find function to the filter function and will add the result to the original array.
try this
const arr1 = [
{
id: 1,
value: { total: 0 },
},
{
id: 2,
value: { total: 0 },
},
{
id: 3,
value: { total: 0 },
},
{
id: 4,
value: { total: 0 },
}
]
const arr2 = [
{
id: 2,
value: 3 ,
},
{
id: 3,
value: 5,
},
];
arr1.map((item) => {
let result = arr2.filter((element) => element.id == item.id)
if(result && result.length) {
item.value.total += result[0].value
}
return item;
});
console.log(arr1)
You have to assign map to your array:
this.arr1 = this.arr1.map((item) => {
this.arr2.find((element) => {
if (element.id === item.id) {
item = {
...item,
value: {
...item.value,
total: item.value.total + element.value,
},
};
console.log(item);
}
});
return item;
});
If each object's id is unique (within each array), you can do:
arr1.forEach((obj1) => {
const obj2Match = arr2.find((obj2) => obj1.id === obj2.id );
if (obj2Match) {
obj1.value.total += obj2Match.value;
}
});
If more than one object can have the same id (e.g. arr2 has two objects that have the id of 2), then you can do:
arr1.forEach((obj1) => {
const obj2Matches = arr2.filter((obj2) => obj1.id === obj2.id );
if (obj2Matches.length) {
obj1.value.total += obj2Matches.reduce(((accum, curr) => accum + curr.value), 0);
}
});
Complexity:
Time: O(N * M)
Space: O(M)
N => arr1.length, M => arr2.length
You could do something like this:
arr2.map((x) => {
let result = arr1.filter((a1) => a1.id === x.id);
if (result.length > 0) {
x.total = result[0].total;
}
return x;
});
I have a similar problem to this (Get a tree like structure out of path string). I tried to use the provided solution but can not get it to work in Angular.
The idea is to the separate incoming path strings (see below) and add them to an object and display them as a tree.
pathStrings: string[] = [
"PathA/PathA_0",
"PathA/PathA_1",
"PathA/PathA_2/a",
"PathA/PathA_2/b",
"PathA/PathA_2/c"
];
let tree: Node[] = [];
for (let i = 0; i < this.pathStrings.length; i++) {
tree = this.addToTree(tree, this.pathStrings[i].split("/"));
}
addToTree(root: Node[], names: string[]) {
let i: number = 0;
if (names.length > 0) {
for (i = 0; i < root.length; i++) {
if (root[i].name == names[0]) {
//already in tree
break;
}
}
if (i == root.length) {
let x: Node = { name: names[0] };
root.push(x);
}
root[i].children = this.addToTree(root[i].children, names.slice(1));
}
return root;
}
The result is supposed to look like this:
const TREE_DATA: Node[] = [
{
name: "PathA",
children: [
{ name: "PathA_0" },
{ name: "PathA_1" },
{
name: "PathA_2",
children: [{ name: "a" }, { name: "b" }, { name: "c" }]
}
]
},
{
name: "PathB",
children: [
{ name: "PathB_0" },
{ name: "PathB_1", children: [{ name: "a" }, { name: "b" }] },
{
name: "PathC_2"
}
]
},
{
name: "PathC",
children: [
{ name: "PathB_0" },
{ name: "PathB_1", children: [{ name: "a" }, { name: "b" }] },
{
name: "PathC_2"
}
]
}
];
Here is the Stackblitz Link (https://stackblitz.com/edit/angular-h3btn5?file=src/app/tree-flat-overview-example.ts) to my intents.. Im trying for days now without success.. Thank you so much!!
In plain Javascript, you could reduce the array by using a recursive function for thesearching and assign then new child to a given node.
const
getTree = (node, names) => {
const name = names.shift();
let child = (node.children ??= []).find(q => q.name === name);
if (!child) node.children.push(child = { name });
if (names.length) getTree(child, names);
return node;
},
pathStrings = ["PathA/PathA_0", "PathA/PathA_1", "PathA/PathA_2/a", "PathA/PathA_2/b", "PathA/PathA_2/c"],
tree = pathStrings
.reduce((target, path) => getTree(target, path.split('/')), { children: [] })
.children;
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would like to filter an array of objects according to the highest value of "value" key and distinct each object by their "id" key.
Example :
var array = [
{
id: 1,
value: 10
},
{
id: 1,
value: 2
},
{
id: 2,
value: 6
},
{
id: 2,
value: 5
},
{
id: 2,
value: 1
}
]
And the expected output:
array = [
{
id: 1,
value: 10
},
{
id: 2,
value: 6
}
]
Thanks
You could reduce the array and check if an object exist with the same id and update if necessary. This approach takes the objects with the largest value.
const
array = [{ id: 1, value: 10 }, { id: 1, value: 2 }, { id: 2, value: 6 }, { id: 2, value: 5 }, { id: 2, value: 1 }],
result = array.reduce((r, o) => {
const index = r.findIndex(({ id }) => o.id === id);
if (index === -1) r.push(o);
else if (r[index].value < o.value) r[index] = o;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another approach with a Map.
const
array = [{ id: 1, value: 10 }, { id: 1, value: 2 }, { id: 2, value: 6 }, { id: 2, value: 5 }, { id: 2, value: 1 }],
result = Array.from(
array.reduce((m, { id, value }) => m.set(id, m.has(id)
? Math.max(m.get(id), value)
: value
), new Map),
([id, value]) => ({ id, value })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here is a possible way to doing this
var array = [
{
id: 1,
value: 10
},
{
id: 1,
value: 2
},
{
id: 2,
value: 6
},
{
id: 2,
value: 5
},
{
id: 2,
value: 1
}
]
let objdis = {};
array.forEach(val => {
if(objdis[val.id] !== undefined){
objdis[val.id].push(Number(val.value));
}else{
objdis[val.id] = [];
objdis[val.id].push(val.value);
}
})
let returningObj = [];
for (prop in objdis){
let obj = {};
obj.id = Number(prop);
obj.Value = Math.max(...objdis[prop])
returningObj.push(obj);
}
console.log(returningObj);
i hope this helps
var arr = [
{
id: 1,
value: 10
},
{
id: 1,
value: 2
},
{
id: 2,
value: 6
},
{
id: 2,
value: 5
},
{
id: 2,
value: 1
}
];
const output = Object.values(arr.reduce((x, y) => {
x[y.id] = x[y.id] && x[y.id].value > y.value ? x[y.id] : y
return x
}, {}));
console.log(output);
There's my answer, but it needs to have sorted indexes and isn't as cool as reduce examples You got here.
var array = [
{
id: 1,
value: 10
},
{
id: 1,
value: 1
},
{
id: 2,
value: 1
},
{
id: 2,
value: 5
},
{
id: 2,
value: 35
},
{
id: 3,
value: 4
},
{
id: 3,
value: 14
},
{
id: 2,
value: 123
}
];
function getHighestValues(Arr) {
var newArr = [];
var IdArr = Arr.map(elem => elem.id);
IdArr.sort((a,b)=>a-b);
for(var i = 0; i < Arr.length; i++) {
let currIdIndex = IdArr.indexOf(Arr[i].id);
if(newArr[currIdIndex] == undefined) {
newArr.push(
{
id: Arr[i].id,
value: Arr[i].value
})
} else if(newArr[currIdIndex].value < Arr[i].value) {
newArr[currIdIndex].value = Arr[i].value;
}
IdArr.splice(currIdIndex, 1);
if(IdArr.indexOf(Arr[i].id) == -1) {
IdArr.splice(currIdIndex, 0, Arr[i].id);
}
}
return newArr;
}
array = getHighestValues(array);
console.log(array);
I'm attempting to convert an array that I get in this format:
data = [
{ name: 'Buttons/Large/Primary', id: '1:23' },
{ name: 'Buttons/Large/Secondary', id: '1:24' },
{ name: 'Buttons/Medium/Primary', id: '1:25' },
{ name: 'Buttons/Medium/Secondary', id: '1:26' },
{ name: 'Forms/Text', id: '2:1' },
{ name: 'Forms/Checkbox', id: '2:2' },
];
to an array in this format:
data = [
{
name: "Buttons",
id: '1:23',
components: [{
name: "Large",
id: '1:23',
components: [{
name: "Primary",
id: '1:23'
}, {
name: "Secondary",
id: '1:24'
}]
},{
name: "Medium",
id: '1:25',
components: [{
name: "Primary",
id: '1:25'
}, {
name: "Secondary",
id: '1:26'
}]
}]
}, {
name: "Forms",
id: '2:1',
components: [{
name: "Text",
id: '2:1'
},{
name: "Checkbox",
id: '2:2'
}]
}
];
My approach was to create arrays from each object in the original dataset by splitting the name property at '/', then nest them inside each other. This is what I have so far, which nests each item in the original array, but lacks grouping them together like my target format shows. Suggestions?
function nestItems(obj, path, value) {
let component = {};
let temp = component;
for (let i = 0; i < path.length; i++) {
let component = temp;
component.name = path[i];
component.id = value;
if (path.length - 1 === i) {
} else {
component.components = {};
temp = component.components;
}
}
obj.push(component)
}
let obj = [];
for (let i = 0; i < data.length; i++) {
let path = data[i].name.split('/');
nestItems(obj, path, data[i].id);
}
console.log(obj)
I agree with your approach for splitting with /.
Here's my approach for using reduce to create a map and generating the final array:
const data = [
{ name: 'Buttons/Large/Primary', id: '1:23' },
{ name: 'Buttons/Large/Secondary', id: '1:24' },
{ name: 'Buttons/Medium/Primary', id: '1:25' },
{ name: 'Buttons/Medium/Secondary', id: '1:26' },
{ name: 'Forms/Text', id: '2:1' },
{ name: 'Forms/Checkbox', id: '2:2' },
];
const map = data.reduce((acc, curr) => {
const { id } = curr;
const [parent, sub, subSub] = curr.name.split('/');
if (acc[parent]) {
if (acc[parent][sub]) {
acc[parent][sub][subSub] = { id };
} else {
acc[parent][sub] = { id };
if (subSub) {
acc[parent][sub][subSub] = { id };
}
}
} else {
acc[parent] = { id };
if (sub && subSub) {
acc[parent][sub] = {
id,
[subSub]: { id }
};
} else if (sub) {
acc[parent][sub] = { id };
};
}
return acc;
}, {});
const result = Object.keys(map).map(parentName => {
const { id: parentId, ...subs } = map[parentName];
const parentObj = { name: parentName, id: parentId };
parentObj.components = Object.keys(subs).map(subName => {
const { id: subId, ...subSubs } = subs[subName];
const subObj = { name: subName, id: subId };
if (Object.keys(subSubs).length) {
subObj.components = Object.keys(subSubs).map(subSubName => ({ name: subSubName, id: subSubs[subSubName].id }));
}
return subObj;
});
return parentObj;
});
console.log(result);
Trying to implement a tree search function which takes an array(tree structure) and a string keyword, would return an tree array but only keep the matched nodes and its parents.
function search(nodes, keyword){
}
const nodes = [
{
value: "1-1",
children: [
{ value: "1-1-1"},
{ value: "1-1-2", children:[
{
value: "1-1-2-1",
children: [
{ value: "1-1-2-1-1" },
{ value: "1-1-2-1-2" }
]
},
{
value: "1-1-2-2"
}
] }
]
},
{
value: "1-2",
children: [
{ value: "1-2-1"},
{ value: "1-2-2", children:[
{
value: "1-2-2-1",
children: [
{ value: "1-2-2-1-1" },
{ value: "1-2-2-1-2" }
]
},
{
value: "1-2-2-2"
}
] }
]
},
];
expected output would be an tree with nodes' values contain "1-1-2-1" and its parents as below
const searchedNodes = search(nodes, "1-1-2-1");
[
{
value: "1-1",
children: [
{ value: "1-1-2", children:[
{
value: "1-1-2-1",
children: [
{ value: "1-1-2-1-1" }
]
}
] }
]
}
]
*/
2018-06-26 Updated
I made a working one(DFS) but probably not pretty efficient.
const search = (nodes, keyword) => {
let newNodes = [];
for (let n of nodes) {
if (n.children) {
const nextNodes = this.keywordFilter(n.children, keyword);
if (nextNodes.length > 0) {
n.children = nextNodes;
} else if (n.label.toLowerCase().includes(keyword.toLowerCase())) {
n.children = nextNodes.length > 0 ? nextNodes : [];
}
if (
nextNodes.length > 0 ||
n.label.toLowerCase().includes(keyword.toLowerCase())
) {
newNodes.push(n);
}
} else {
if (n.label.toLowerCase().includes(keyword.toLowerCase())) {
newNodes.push(n);
}
}
}
return newNodes;
};
You need to iterate the nodes of the same level and check if the value is equal, then take that node and exit the loop. Otherwise check the children and generate a new object for preventing to mutate the original data.
function search(nodes, value) {
var result;
nodes.some(o => {
var children;
if (o.value === value) {
return result = o;
}
if (o.children && (children = search(o.children, value))) {
return result = Object.assign({}, o, { children });
}
});
return result && [result];
}
const nodes = [{ value: "1-1", children: [{ value: "1-1-1" }, { value: "1-1-2", children: [{ value: "1-1-2-1", children: [{ value: "1-1-2-1-1" }, { value: "1-1-2-1-2" }] }, { value: "1-1-2-2" }] }] }, { value: "1-2", children: [{ value: "1-2-1" }, { value: "1-2-2", children: [{ value: "1-2-2-1", children: [{ value: "1-2-2-1-1" }, { value: "1-2-2-1-2" }] }, { value: "1-2-2-2" }] }] }];
console.log(search(nodes, "1-1-2-1"));
.as-console-wrapper { max-height: 100% !important; top: 0; }