Merge nested relations to an Object - javascript

I have an array of objects that also contains array like this:
let array = [{"a": ["b", "c"]} , {"b":[ "d" ]}, {"e":[ "f" ]}]
I need to display it as Tree View and I need to get the output like below:
[
{
id : "a",
children: [
{
id: "b",
children: [{id: "d", children: [] }]
},
{
id: "c",
children: []
}
]
},
{
id: "e",
Children: [
{
id: "f",
children: []
}
]
}
]
I tried to do it by creating an array of all the parents [a, b, e], and depth first search through the entire array but I could not get the correct output.
Can someone help? Thanks in advance.

Try this recursive approach:
var array = [{ "a": ["b", "c"] }, { "b": ["d"] }, { "e": ["f"] }]
let object = {}
array.map(itm => Object.keys(itm).map(name => object[name] = itm[name]))
const treeView = (key, val) => {
delete object[key]
return {
id: key,
children: getChildrens(val)
}
}
const getChildrens = (arr) => {
let childrens = []
return arr.map(itm => {
if (object[itm]) {
return treeView(itm, object[itm])
}
return { id: itm, children: [] }
})
}
let res = Object.keys(object).map((val, idx) => {
if (object[val])
return treeView(val, object[val])
}).filter(e=>e)
console.log(res)

Related

Move objects in array where duplicates occur

I have an array of objects, each array has a key of name and then another array of objects:
const myArray = [ { name: "1", item: [{}] }, { name: "2", item: [{}] }, { name: "1", item: [{}] } ]
Now for example sometimes that name key will be the same, i want to be able to check if that name exists and if it does exist push the item into that array object and not into a new object.
The behaviour im getting is above but i would like:
const myArray = [ { name: "1", item: [{ item1, item2 etc }] }, { name: "2", item: [{}] }, { name: "3", item: [{}] } ]
Thanks so much in advance!
You can get the desired result using Array.reduce(), grouping by name.
If two objects in myArray share the same name, the item values are combined.
const myArray = [ { name: "1", item: [{ id: 1 }] }, { name: "2", item: [{ id: 2}] }, { name: "1", item: [{ id: 3}] } ]
const result = Object.values(myArray.reduce((acc, { name, item }) => {
acc[name] = acc[name] || { name, item: [] };
acc[name].item.push(...item);
return acc;
}, {}))
console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }
Here's a solution using Array.prototype.reduce function.
const myArray = [ { name: "1", item: [{}] }, { name: "2", item: [{}] }, { name: "1", item: [{}] } ];
const output = myArray.reduce((acc, curr) => {
const index = acc.findIndex(pre => pre.name === curr.name);
if(index !== -1) {
acc[index].item = acc[index].item.concat(curr.item);
} else {
acc.push(curr);
}
return acc;
}, []);
console.log(output);

Find all occurance of keys in the object and change the value

I want to find all occurances of keys and change its value. I want the id and name to be changed in the entire object to a new value.
const myObj = {
id: 1,
name: "a",
children: [
{
id: 2,
name: "b",
children: [
{
id: 3,
name: "c",
}
]
},
{
id: 4,
name: "d",
children: [
{
id: 5,
name: "e",
children: [
{
id: 6,
name: "f",
children: [
{
id: 7,
name: "g",
}
]
}
]
}
]
},
]
}
Code which i tried, not sure how can i get two properties and change their values.
function findAllByKey(obj, id, name) {
let constObj = Object.entries(obj);
console.log(obj)
Object.entries(constObj)
.reduce(([key, value]) => (key === id)
? obj[key] = "123"
: (typeof value === 'object'))
return obj;
}
// USAGE,
console.log(findAllByKey(myObj, 'id', 'name'))
You will need to utilize recursion for this.
Dave Newton gives a good argument in saying that the children properties are the ones containing most of the properties you want to change, so I would recommend you loop through each of the children properties and change their ID in that way. However, the answer I give you will work in more generic instances (for those who may need a different approach).
function findAllByKeyAndReplace(object,key,replace){
const looper = function(obj){
for (let k in obj){
if(k === key){
obj[k] = replace;
}
else if("object" === typeof obj[k]){
looper(obj[k]);
}
}
}
looper(object);
}
const myObj = {
id: 1,
name: "a",
children: [
{
id: 2,
name: "b",
children: [
{
id: 3,
name: "c",
}
]
},
{
id: 4,
name: "d",
children: [
{
id: 5,
name: "e",
children: [
{
id: 6,
name: "f",
children: [
{
id: 7,
name: "g",
}
]
}
]
}
]
},
]
}
findAllByKeyAndReplace(myObj,"id","123");
findAllByKeyAndReplace(myObj,"name","pickles");
console.log(myObj);
Note that I am pretty old school about this so please tell me if there is any way to improve on this, as it does take up a bit of power.
Oh wait, I see you want to return a list of the objects and not bulk-replace them with one value. Ok, that is quite easily done, too.
Instead of changing them just add them to an array which will be returned on the looper being finished:
function findAllByKey(object, key) {
const collection = [];
const looper = function(obj) {
for (let k in obj) {
if (k === key) {
collection.push(obj[k]);
} else if ("object" === typeof obj[k]) {
looper(obj[k]);
}
}
}
looper(object);
return collection;
}
const myObj = {
id: 1,
name: "a",
children: [{
id: 2,
name: "b",
children: [{
id: 3,
name: "c",
}]
},
{
id: 4,
name: "d",
children: [{
id: 5,
name: "e",
children: [{
id: 6,
name: "f",
children: [{
id: 7,
name: "g",
}]
}]
}]
},
]
}
console.log(findAllByKey(myObj, "id"));
console.log(findAllByKey(myObj, "name"));

Map over two arrays of objects, match properties and store specific info in a new array

New to javascript and trying to learn! I am trying to map through two array of objects, and if a certain property matches, pull in specific information into an array.
let result;
let arrNames = [{
name: "A"
}, {
name: "B"
}, {
name: "C"
}]
let arrInfo = [{
name: "A",
info: "AAA"
}, {
name: "B",
info: "BBB"
}, {
name: "C",
info: "ccc"
}]
If arrNames.name == arrInfo.name, I would like result to equal arrInfo.info.
What I've tried:
arrNames.map(x => {
if(arrNames.name == arrInfo.name){
result=arrInfo.info
}
^ This obviously doesn't work -- but I'm wondering if Assign or Filter would be appropriate.
Thanks in advance for your help (apologies that this is probably a dupe)!
You can use find() inside map() to find the element. This finds the element even if they aren't at the same index in both arrays.
Then use filter() to filter any undefined values which will be present if there isn't a match.
var arrNames = [
{name: "A"},
{name: "B"},
{name: "C"}
];
var arrInfo = [
{name: "A", info: "AAA"},
{name: "B", info: "BBB"},
{name: "C", info: "ccc"}
];
let result = arrNames.map(x => {
item = arrInfo.find(item => item.name === x.name);
if (item) {
return item.info;
}
}).filter(item => item !== undefined); // Can also use filter(item => item);
console.log(result);
let result = [];
arrNames = [
{name: "A"},
{name: "B"},
{name: "C"},
]
arrInfo = [
{name: "A", info: "AAA"},
{name: "B", info: "BBB"},
{name: "C", info: "ccc"},
]
result = arrNames.map(function(_, index){
if(arrNames[index].name === arrInfo[index].name) {
return arrInfo[index].info
}
})
You can use map with a condition inside
el.name === arrNames[index].name && el.info
Means:
if (el.name === arrNames[index].name) return el.info
let arrNames = [{
name: "A"
}, {
name: "B"
}, {
name: "C"
}]
let arrInfo = [{
name: "A",
info: "AAA"
}, {
name: "B",
info: "BBB"
}, {
name: "C",
info: "ccc"
}]
const res = arrInfo.map((el, index) => el.name === arrNames[index].name && el.info)
console.log(res)

create an array of objects based on another array of objects programmatically

here is the array of objects I have:
var sentences = [
{ id: "1-1", layer: ["A"] },
{ id: "1-2", layer: ["B"] },
{ id: "1-3", layer: ["C"] },
{ id: "2-1", layer: ["D"] },
{ id: "2-2", layer: ["E"] },
{ id: "2-3", layer: ["F"] },
{ id: "3-1", layer: ["G"] },
{ id: "3-2", layer: ["H"] },
{ id: "3-3", layer: ["I"] },
];
the first number in id is the slide number and the second one is for the sentence on that slide. for example id: 3-2 is slide 3 and sentence 2.
so we have 3 slides here...
Now the problem is How can I programmatically fill the slides array like this:
var slides = [
{ slide_id: "1", slide_layer: ["A", "B", "C"] },
{ slide_id: "2", slide_layer: ["D", "E", "F"] },
{ slide_id: "3", slide_layer: ["G", "H", "I"] },
]
I'm still researching but I can't find a proper way...
You can use reduce method to group slides by id using object as accumulator, and then you can get array of values from that object with Object.values method.
var sentences = [{"id":"1-1","layer":["A"]},{"id":"1-2","layer":["B"]},{"id":"1-3","layer":["C"]},{"id":"2-1","layer":["D"]},{"id":"2-2","layer":["E"]},{"id":"2-3","layer":["F"]},{"id":"3-1","layer":["G"]},{"id":"3-2","layer":["H"]},{"id":"3-3","layer":["I"]}]
const result = Object.values(sentences.reduce((r, {id, layer}) => {
let [a, b] = id.split('-');
if(!r[a]) r[a] = { slide_id: a, slide_layer: [] }
r[a].slide_layer[b - 1] = layer[0]
return r;
}, {}))
console.log(result)
We can use Array.prototype.reduce to accumulate the slides from the sentences array. We need to test if the slide object is already there or not in the accumulator array using Array.prototype.findIndex() and slide_id.
If it is present (idx is >= 0) we need to add the layer to the slide_layer array property of the slide object.
var sentences = [
{ id: "1-1", layer: ["A"] },
{ id: "1-2", layer: ["B"] },
{ id: "1-3", layer: ["C"] },
{ id: "2-1", layer: ["D"] },
{ id: "2-2", layer: ["E"] },
{ id: "2-3", layer: ["F"] },
{ id: "3-1", layer: ["G"] },
{ id: "3-2", layer: ["H"] },
{ id: "3-3", layer: ["I"] },
];
var slides = sentences.reduce((acc, ele) => {
let idx = acc.findIndex(obj => obj.slide_id === ele.id.split("-")[0]);
if(idx >= 0){
let obj = acc[idx];
obj.slide_layer.push(ele.layer[0]);
}else{
acc.push({slide_id: ele.id.split("-")[0], slide_layer : [ele.layer[0]]});
}
return acc;
}, []);
console.log(slides);
Here is the solution with easy to read code.
let slides = [];
for(let data of sentences) {
let slideId = parseInt(data.id.split("-")[0]);
let slideIndex = slideId-1;
if (!slides[slideIndex]) slides[slideIndex] = {"slide_id": slideId, "slide_layer": []}
slides[slideIndex].slide_layer.push(data.layer[0]);
}
console.log("slides", slides);
The array reduce() method in JavaScript is used to reduce the array to a single value and executes a provided function for each value of the array (from left-to-right) and the return value of the function is stored in an accumulator.
const output = Object.values(sentences.reduce((k, {id, layer}) => {
let [frst, sec] = id.split('-');
if(!k[frst])
k[frst] = { slide_id: frst, slide_layer: [] }
k[frst].slide_layer[sec - 1] = layer[0]
return k;
}, {}))

How to transform the tree data into one-line-data using rxjs

I have a problem here:
for example, the tree data:
[{
key: 1,
value: 1,
children: [{
key: 11,
value: 11: children: []
}]
},
{
key: 2,
value: 2,
children: []
}]
Now I want this:
[{key:1,value:1},{key:11,value:11},{key:2,value:2}]
How to deal with that using rxjs or something else? Any opinion will be appreciated.
You could make a depth first recursive traversal of the tree with something like. This makes assumptions that your input data is consistent.
let arr = [{key: 1,value: 1,children: [{key: 11,value: 11,children: []}]},{key: 2,value: 2,children: []}]
function flatTree(arr){
return arr.reduce((res, {key, value, children} ) =>
res.concat({key, value}, ...flatTree(children))
, [])
}
console.log(flatTree(arr))
You can also do this in a single nested reduce():
let arr = [{key: 1,value: 1,children: [{key: 11,value: 11,children: []}]},{key: 2,value: 2,children: []}]
let r = arr.reduce(function flatTree(res, {key, value, children} ) {
return res.concat({key, value}, ...children.reduce(flatTree, []))
}, [])
console.log(r)
Create a recursive function & loop through the array. While looping check if the current key-value is an array or not. If it is an array then call the recusrive function again with new data
let data = [{
key: 1,
value: 1,
children: [{
key: 11,
value: 11,
children: []
}]
},
{
key: 2,
value: 2,
children: []
}
]
let finalArray = [];
function formatData(data) {
data.forEach((item) => {
let obj = {};
for (let keys in item) {
if (Array.isArray(item[keys])) {
formatData(item[keys])
} else {
obj[keys] = item[keys];
}
}
finalArray.push(obj)
})
}
formatData(data);
console.log(finalArray)

Categories

Resources