How to write Logic for given output? - javascript

I am trying to write a logic for given input and I need desired output in JavaScript.
Given Input:
var test = [{parentId:1,subId:1,subSubId:1},
{parentId:1,subId:2,subSubId:null},
{parentId:1,subId:null,subSubId:null},
{parentId:2,subId:1,subSubId:1},
{parentId:2,subId:null,subSubId:null}];
Expected output:
{
"category": [
{
"parentId": 1,
"subCatgory": [
{
"subId": 1,
"subSubCategory": [
{
"subSubId": 1
}
]
},
{
"subId": 2
}
]
},
{
"parentId": 2,
"subCatgory": [
{
"subId": 1
}
]
}
]
}

This code can perform that:
const test = [{
parentId: 1,
subId: 1,
subSubId: 1
},
{
parentId: 1,
subId: 2,
subSubId: null
},
{
parentId: 1,
subId: null,
subSubId: null
},
{
parentId: 2,
subId: 1,
subSubId: 1
},
{
parentId: 2,
subId: null,
subSubId: null
}
];
const parse = (data) => {
const category = data.reduce((acc, { parentId, subId, subSubId }) => {
let parent = acc.find(v => v.parentId === parentId)
if (!parent) {
parent = { parentId, subCategory: [] }
acc.push(parent)
}
if (!subId) return acc
let subCatetogy = parent.subCategory.find(v => v.subId === subId)
if (!subCatetogy) {
subCatetogy = { subId }
parent.subCategory.push(subCatetogy)
}
if (!subSubId) return acc
subCatetogy.subSubCategory = subCatetogy.subSubCategory || []
subCatetogy.subSubCategory.push({ subSubId })
return acc
}, [])
return { category }
}
console.log(parse(test))
Note: it seems like you've misspelled subCatgory so I've changed it to subCategory. And also parentId: 2 has subSubId: 1 in my solution, although it's in your test variable, but it seems missing in your desirable result.
Hope you find my answer useful :)

This code does what you need to do. It also works when subId and subSubId are both null. Please check:
const testData = [
{
parentId: 1,
subId: 1,
subSubId: 1
},
{
parentId: 1,
subId: 2,
subSubId: null
},
{
parentId: 1,
subId: null,
subSubId: null
},
{
parentId: 2,
subId: 1,
subSubId: 1
},
{
parentId: 2,
subId: null,
subSubId: null
},
{
parentId: 3,
subId: null,
subSubId: null,
}
];
function generateData(data) {
/**
* This will generate a map of objects that looks like this:
* map = {
* // parentId
* 1: {
* // subId
* 1: [
* // subSubId
* 1,
* 2,
* ...
* ],
* ...
* },
* ...
* }
*/
const map = data.reduce((result, { parentId, subId, subSubId }) => {
if (result[parentId]) {
if (!subId) return result;
if (result[parentId][subId]) {
if (!subSubId) return result;
result[parentId][subId].push(subSubId);
} else {
result[parentId][subId] = subSubId ? [subSubId] : [];
}
} else {
if (subId) {
result[parentId] = { [subId]: subSubId ? [subSubId] : [] };
} else {
result[parentId] = {};
}
}
return result;
}, {});
const categories = Object.keys(map).map(parentId => {
const parent = map[parentId];
const category = { parentId };
const subCategories = Object.keys(parent).map(subId => {
const subSubs = parent[subId];
const subCategory = { subId };
if (subSubs.length) {
subCategory.subSubCategory = subSubs.map(subSubId => ({ subSubId }));
}
return subCategory;
});
if (subCategories.length) {
category.subCategory = subCategories;
}
return category;
});
return { category: categories };
}
const result = generateData(testData);
console.log(result);
I added some comments so you can understand it easily, but it would take a bit of time to fully understand the logic.

Related

Being able to remove duplicate keys from an array of objects

I have a question about how I can delete the existing elements, for example, in my case "Tallas" is repeated, could you please help me? Thank you very much to those who are willing to help me to solve this problem
const data =
[ { atributos: { Tallas: [{ id: 0, name: 'XS' }, { id: 1, name: 'S' }] }}
, { atributos: { Calzado: [{ id: 0, name: '10' }, { id: 1, name: '9.5' }] }}
, { atributos: { Tallas: [{ id: 0, name: 'XS' }] }}
]
The idea is to have this json format with the last "Tallas" since it is the last one that I added through my dynamic form.
const expected =
[{ atributos: { Calzado: [{ id: 0, name: '10' }, { id: 1, name: '9.5' }] }}
, { atributos: { Tallas: [{ id: 0, name: 'XS' }] }}
]
How do I do this is there a way to do it, I've tried with filter plus the findindex but I can't get to eliminate the repetition of the json res= new.filter((arr, index, self) => index === self.findIndex( (t) => (t.attributes === arr.attributes )))
To unique the array of objects, we can use the Javascript Set module, if the array has complex nested objects, we can stringify each object before creating new Set data. this below function will unique the array of complex objects.
function unique_array(array = []) {
const newSetData = new Set(array.map((e) => JSON.stringify(e)));
return Array.from(newSetData).map((e) => JSON.parse(e));
}
this is a function that takes an array and return the same array but delete every duplicated item
function removeDuplicates(arr) {
return arr.filter((item,
index) => arr.indexOf(item) === index);
}
I didn't understant the part written in spanish so I hope this is what you are looking for
This is a solution specific to your question. this is not a generic solution.
const data = [
{
atributos: {
Tallas: [
{ id: 0, name: "XS" },
{ id: 1, name: "S" },
],
},
},
{
atributos: {
Calzado: [
{ id: 0, name: "10" },
{ id: 1, name: "9.5" },
],
},
},
{
atributos: {
Tallas: [
{ id: 0, name: "XS" },
{ id: 1, name: "S" },
],
},
},
];
function uniqueArray(array) {
const resultObject = array.reduce((acc, eachValue) => {
let keys = Object.keys(eachValue.atributos);
keys.forEach((eachKey) => {
if (!acc[eachKey]) {
acc[eachKey] = [];
}
let list = eachValue["atributos"][eachKey].map(
(each) => each.id + "-" + each.name
);
acc[eachKey].push(...list);
});
return acc;
}, {});
const resultArray = Object.keys(resultObject).reduce((acc, each) => {
let setData = Array.from(new Set(resultObject[each]));
acc.push({
atributos: {
[each]: setData.map((e) => {
return { id: e.split("-")[0], name: e.split("-")[1] };
}),
},
});
return acc;
}, []);
return resultArray;
}
const result = uniqueArray(data)
console.log("result ", JSON.stringify(result, null, 2));

Check object for duplicate id and combine into new object

I have an array like the picture, now i want to check if the id is duplicate then combine it and the value of "key" will become key with the value is 1 or 0
final result :
[
{
id: 4,
view: 1,
add: 1,
edit: 1,
delete: 0,
},
{
id: 7,
view: 1,
add: 1,
edit: 0,
delete: 0,
},
];
code
const App = () => {
const arr = [
{ id: 4, key: "view" },
{ id: 4, key: "add" },
{ id: 7, key: "view" },
{ id: 7, key: "add" },
{ id: 4, key: "edit" }
];
arr.map((item,index) => {
// check the next id is exists
if(arr[index + 1] && item.id === arr[index + 1].id) {
//
}
})
return (
<div></div>
);
};
create a object template which initialises all the values to zero.
reduce over the array of objects. If the id is not found on the initial object as a key add it, and set its value to an object containing the id, and a merged copy of template.
Set any found keys to 1.
Grab the resulting object's values to get an array of objects matching your expected output.
const arr = [
{ id: 4, key: "view" },
{ id: 4, key: "add" },
{ id: 7, key: "view" },
{ id: 7, key: "add" },
{ id: 4, key: "edit" }
];
// Create an object template
const tmpl = { view: 0, add: 0, edit: 0, delete: 0 };
// `reduce` over the array of objects. If the id
// doesn't exist on the initialised object as a key
// add it and set it's value to an object containing
// the id, and a copy of the object template, and
// then update any keys that are found.
const obj = arr.reduce((acc, c) => {
const { id, key } = c;
acc[id] ??= { id, ...tmpl };
acc[id][key] = 1;
return acc;
}, {});
console.log(Object.values(obj));
Additional documentation
Logical nullish assignment
Spread syntax
Destructuring assignment
const data = [
{ id: 4, key: "view" },
{ id: 4, key: "add" },
{ id: 7, key: "view" },
{ id: 7, key: "add" },
{ id: 4, key: "edit" }
]
const result = data.reduce((p, c) => {
const found = p.findIndex(p => p.id === c.id);
if (found !== -1) {
p[found][c.key] = 1;
} else {
const tmpObj = {
id: c.id,
view: 0,
add: 0,
edit: 0,
delete: 0
}
tmpObj[c.key] = 1;
p.push(tmpObj)
}
return p;
}, []);
console.log(result);
const arr = [
{ id: 4, key: "view" },
{ id: 4, key: "add" },
{ id: 7, key: "view" },
{ id: 7, key: "add" },
{ id: 4, key: "edit" }
];
const r = arr.reduce((c, d, i) => {
const {
id,
key
} = d;
if (c[id]) {
c[id][key] = 1
} else {
c[id] = {
id,
view: 0,
edit: 0,
add: 0,
delete: 0
}
c[id][key] = 1
}
return c
}, {});
const result = Object.values(r);
console.info(result)

How to iterate through a list using recursion

I've got a list like this below and I'm trying to get a list of all subnodes. I need to find all children and subchildren of a list. In this case it should return exact this list.
const data = [
{
id: 1,
parent: 0,
},
{
id: 2,
parent: 1,
},
{
id: 3,
parent: 1,
},
{
id: 4,
parent: 3,
}
];
I'm trying to choose whether or not call the function again in many ways but the result is always wrong.
const getNodes = (n) => {
let family = [];
for (let i of n) {
const sons = data.filter(x => x.parent === i.id);
if (sons.length !== 0) {
family.push(getNodes(sons));
} else {
family.push(i);
}
}
return family;
};
console.log(getNodes([data[0]]));
Let's transform that to a tree.
const data = [{
id: 1,
parent: 0,
},
{
id: 2,
parent: 1,
},
{
id: 3,
parent: 1,
},
{
id: 4,
parent: 3,
}
];
// first obj of nodes grouped by id
var obj_nodes = data.reduce(function(agg, item) {
agg[item.id] = { ...item, children: [] };
return agg;
}, {})
// console.log(obj_nodes)
// connecting edges (child parent relations)
data.forEach(function(item) {
var source = obj_nodes[item.id];
var destination = obj_nodes[item.parent];
destination && destination.children.push(source);
}, {})
var trees = Object.values(obj_nodes);
var result = trees[0]
console.log(result)
.as-console-wrapper {max-height: 100% !important}

Javascript match two arrays by id

The goal is to match two arrays by id. I need to check if stopId is in both info and times arrays and combine matching arrays.
What should be the proper check to find out if id matches? I've attached an example, I was trying to implement using includes.
Could you please give me an advise?
const info = [
{
stopId: 1,
name: "N1"
},
{
stopId: 2,
name: "N2"
},
{
stopId: 3,
name: "N3"
}
]
const times = [
{
stopId: 1,
time: "T1"
},
{
stopId: 3,
time: "T2"
}
]
// Expected
// [
// {
// stopId: 1,
// name: "123",
// time: "T1"
// },
// {
// stopId: 2,
// name: "123"
// },
// {
// stopId: 3,
// name: "123",
// time: "T2"
// }
// ]
const res = () => {
const final = [];
info.forEach((item) => {
if (times.includes(item.stopId)) { // How to check if stopId matches
final.push({ })
}
})
}
console.log(res())
Try this one:
const result = info.map((item) => {
const time = times.find((time) => time.stopId === item.stopId)
return {
...item,
time: time ? time.time : null
}
})
Attached a working example
const info = [{
stopId: 1,
name: "N1"
},
{
stopId: 2,
name: "N2"
},
{
stopId: 3,
name: "N3"
}
]
const times = [{
stopId: 1,
time: "T1"
},
{
stopId: 3,
time: "T2"
}
]
// Expected
// [
// {
// stopId: 1,
// name: "123",
// time: "T1"
// },
// {
// stopId: 2,
// name: "123"
// },
// {
// stopId: 3,
// name: "123",
// time: "T2"
// }
// ]
const res = () => {
const final = [];
info.forEach((item) => {
let temp = { ...item
};
times.forEach((el) => {
if (item.stopId === el.stopId) {
temp = { ...temp,
...el
};
}
})
final.push(temp);
})
console.log(final);
}
res()
With includes you are comparing the objects of time to the stopId of the item. You have to select the stopId of the time first. You can use the operator find for example:
info.forEach((item) => {
if (times.find(t => t.stopId === item.stopId)) {
final.push({ })
}
})
You should try this code
var record1 = [
{
id: 66,
name: 'haris'
},
{
id: 873,
name: 'laxman'
},
]
var record2 = [
{
id: 99,
name: 'arjit'
},
{
id: 873,
name: 'laxman'
},
]
var result = record1.filter((elem, index) => elem.id == record2[index].id );

How to convert `pid` in json array into array of `children` form?

Raw array:
const data1 = [
{
id: 1,
pid: 0
},
{
id: 2,
pid: 1
},
{
id: 3,
pid: 2
}
]
How to convert pid in json array into array of children form?
How to turn him into:
[
{
id: 1,
pid: 0,
children: [
{
id: 2,
pid: 1,
children: [
{
id: 3,
pid: 2
}
]
}
]
}
]
-----------------------------------
He recognizes children by pid
How to write a function to do it?
thanks
const data = [
{
id: 1,
pid: 0
},
{
id: 4,
pid: 3
},
{
id: 2,
pid: 1
},
{
id: 3,
pid: 2
}
];
function toTree (data) {
data.forEach(function(item) {
delete item.children;
});
const map = {};
data.forEach(function(item) {
map[item.id] = item;
});
let val = [];
data.forEach(function(item) {
const parent = map[item.pid];
if(parent) {
(parent.children || (parent.children = [])).push(item);
} else {
val.push(item);
}
});
return val;
}
console.log(JSON.stringify(toTree(data)));
Refer to #chiliNUT answer, add a method :
const data1 = [
{
id: 1,
pid: 0
},
{
id: 4,
pid: 2
},
{
id: 5,
pid: 1
},
{
id: 3,
pid: 2
},
{
id: 2,
pid: 1
}
];
function toTree (data){
data.sort((a, b) => (a.pid - b.pid === 0) ? a.id - b.id : a.pid - b.pid);
const map = {}
data.forEach(item => (map[item.pid] || (map[item.pid] = []) ).push(item))
const mapArr = Object.values(map)
mapArr.reduce((a, b, index, arr) => {
if ( a[0].id === b[0].pid) { // There are still bugs here
a[0].children = b
}
return b;
})
return mapArr[0]
}
console.log(JSON.stringify(toTree(data1)));
data1.reduce((el1, el2)=>{el1.children = [el2]; return el2;});
const tree = [data1[0]];
You can use Array.reduce(el1, el2) It iterates over the array like map, except: For the first iteration, el1 and el2 are the first and second elements of the array, then for the iterations after, el1 is return value of the previous iteration, and el2 is the next element of the array. Unlike map, which operates on each element of the array, reduce uses each element of the array to generate a single return value.
data1.reduce((el1, el2)=>{el1.children = [el2]; return el2;});
So that appends all elements of data1 successively to the first element. Your final output should be an array, so
const tree = [data1[0]]
Follow up: if the data is not already sorted by id, you can sort it like this
data1.sort((el1, el2) => {return el1.id > el2.id ? 1 : -1});
const data1 = [
{
id: 1,
pid: 0
},
{
id: 2,
pid: 1
},
{
id: 3,
pid: 2
}
]
data1.reduce((a,b)=>{a.children=[b];return b;});
const tree = [data1[0]];
console.log(tree);
I think the best way is to use recursive to loop on each element and put as child of the previous one.
const data1 = [
{
id: 1,
pid: 0
},
{
id: 2,
pid: 1
},
{
id: 3,
pid: 2
}
];
function convert(arr){
let counter = 0;
let convertedArray = [];
function recursiveFunction(currentObject = null){
if(counter >= arr.length) return convertedArray;
if(currentObject == null){
currentObject = {
children: [arr[0]]
}
convertedArray.push(currentObject);
} else {
currentObject.children = [ arr[counter] ];
}
counter++;
return recursiveFunction(currentObject.children[0]);
}
return recursiveFunction();
}
let newData = convert(data1);
console.log(newData);

Categories

Resources