This question already has answers here:
Build tree array from flat array in javascript
(34 answers)
Javascript: Building a hierarchical tree
(6 answers)
Closed 5 years ago.
I'm trying to make build nested hierarchy from the defined input data, and I`m faced some problem with the deep level hierarchy. So, as an input there is array of objects, looks like this:
[
{
id: 1,
parentId: 1,
},
{
id: 2,
parentId: 1,
},
{
id: 3,
parentId: 2,
},
{
id: 4,
parentId: 3,
},
...
]
Every element has his own id and parentId.
As outcome, I want to have the structure, grouped by the parent id's, smth like this:
{
id: 1,
sub: [
{
id: 2,
parentId: 1,
sub: [
{
id: 3,
parenId: 2,
},
....
],
},
],
}
So, the problem is how to build algorithm that will recursively goes through this input data, and build such structured outcome? When I know the level of hierarchy, I could build algorithm with defined level of nested loops, but the problem is with unknown number of deeper.
Related
This question already has an answer here:
Lodash uniqBy update the latest value
(1 answer)
Closed 9 months ago.
I am working on one project where I need to remove duplicate values from JSON array object with some specification in react JS. I have tried to remove using _.uniqBy but in the output it took very first value from duplicate value which is I don't want.
Suppose You have an array JSON like:
[ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }, { id: 1, name: 'alice' } ]
using _.uniqBy I got [ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }] this output.
but I want [ { id: 2, name: 'bill' }, { id: 1, name: 'alice' } ] this output.
As you can see I want output whose name is alice not bob along with id:1.
Can anyone help me?
Thank you.
My first thought is to use a reduce, and shove the items in a map, then get the values:
Object.values(items.reduce((map, item) => ({ ...map, [item.id]: item }), {}))
This is probably not very efficient though if you're dealing with large arrays of have performance concerns.
It's a quick and dirty one-liner. If you want something more efficient I'd take a look at the lodash source code and tweak it to your needs or write something similar:
https://github.com/lodash/lodash/blob/2f79053d7bc7c9c9561a30dda202b3dcd2b72b90/.internal/baseUniq.js
This question already has answers here:
How can I create every combination possible for the contents of two arrays?
(16 answers)
Cartesian product of multiple arrays in JavaScript
(35 answers)
Closed 1 year ago.
Ive got 3 parent arrays that could sometimes be different lengths which are called Options
Each Option has values array which can also be different lengths
Example of this would be something like this
[
{
name: "Option 1",
values: ["Blue","Red","Orange"]
},
{
name: "Option 2",
values: ["Small","Medium","Large"]
},
{
name: "Option 3",
values: ["Cotton","Satin"]
}
]
The outcome should generate an array like this
[
{
title: "Blue/Small/Cotton",
price: "10.00"
},
{
title: "Blue/Small/Satin",
price: "10.00"
},
{
title: "Blue/Small/Cotton",
price: "10.00"
},
{
title: "Blue/Medium/Satin",
price: "10.00"
},
]
And So on.
Ive tried mapping through the options but knowing the size of the multiple arrays is what I couldnt figure out
SOLUTION
I managed to get a solution
product.options.reduce(
(a, b) => a.flatMap((x) => b.values.map((y) => [...x, y])),
[[]]
);
There is an array of data that needs to be converted to a tree:
const array = [{
id: 5,
name: 'vueJS',
parentId: [3]
}, {
id: 6,
name: 'reactJS',
parentId: [3]
}, {
id: 3,
name: 'js',
parentId: [1]
}, {
id: 1,
name: 'development',
parentId: null
}, {
id: 4,
name: 'oracle',
parentId: [1,2]
}, {
id: 2,
name: 'data-analysis',
parentId: null
}];
Now it works using this function:
function arrayToTree(array, parent) {
var unflattenArray = [];
array.forEach(function(item) {
if(item.parentId === parent) {
var children = arrayToTree(array, item.id);
if(children.length) {
item.children = children
}
unflattenArray.push(item)
}
});
return unflattenArray;
}
console.log(arrayToTree(array, null));
I have two problems with this feature:
The value of "parentId" should be an array of id, for example -
"parentId": [2, 3]
How to transfer to function only one argument - "array"?
https://codepen.io/pershay/pen/PgVJOO?editors=0010
I find this question confusing. It sounds like what you are really saying is the array represents the “definition of node types in the tree” and not the actual instances of those nodes that will be in the tree.
So your problem is you need to copy the “definitions” from the array to new “instance” nodes in your tree. This would let “Oracle” show twice, as you’d create a new “oracle instance” node for each parent in its parent array. It wouldn’t technically need to be a deep copy depending on your use, so you could proof of concept with Object.assign, but each instance would point to the same parents array and that may or may not cause problems for that or future reference values you add to the definition.
Finally, depending on the size of the tree and what you are really trying to do, you might want to convert to a tree represented by nodes/edges instead of parent/children. For really large datasets recursion can sometimes cause you problems.
Sorry I’m on my phone so some things are hard to see on the codepen.
So I have some code which has a requirement of calling xprod with (input, input), similar to as follows:
const input = [
{ id: 1, data: 'a' },
{ id: 2, data: 'b' },
];
const product = xprod(input, input);
/*
[
[ { id: 1, data: 'a' }, { id: 1, data: 'a' } ],
[ { id: 1, data: 'a' }, { id: 2, data: 'b' } ],
[ { id: 2, data: 'b' }, { id: 1, data: 'a' } ],
[ { id: 2, data: 'b' }, { id: 2, data: 'b' } ],
]
*/
I'd like to filter tuples in the list above by comparing the first element of the tuples to the second element in the same tuple. In this case, to remove the tuples which contain objects which have equal ids (so the 0th and 3rd elems should be filtered out -- I know in this simplified example I could use strict equality to filter, too, but that's often not the case in the code I'm actually writing).
I know I can accomplish this pretty simply with lambdas, but since I find myself ending up with this sort of data (lists of tuples) fairly often when working with ramda, I often get stuck on trying to compare one item in a tuple to another item in the same tuple in a points free manner. And maybe that's an argument to just keep it simple and use the lambda, but I'm curious if there's a different way to do it.
Here's a link to a ramda repl containing an implementation.
One option is to simply wrap a function that expects the two arguments of the tuple with R.apply. In your example that could be a partially applied R.eqProps.
R.filter(R.apply(R.eqProps('id')), product)
So I am trying to combine 2 different javascript object than I can end up using in an angularjs ng-repeat . since there is a 1 to many relationship from the database, I was pulling queries separately.
What I have is this:
Main list of data , 3 object sample
0: Object
$$hashKey: "object:4"
Active:true
QuestionId:2
SalesChannel:"DTD"
1: Object
$$hashKey: "object:5"
Active:true
QuestionId:3
SalesChannel:"DTD"
2: Object
$$hashKey: "object:6"
Active:true
QuestionId:5
SalesChannel:"DTD"
Then another query returned data into what I want to relate as JSON into the other object
Object { Id: 3, Name: "Text box" QuestionId: 3}
{ Id: 4, Name: "Text box" QuestionId: 3}
{ Id: 9, Name: "Text box" QuestionId: 5}
So since I have both of these objects , I am wanting to combine.
Naturally I would think that I should return from the database, but then I also think about looping over and appending
for loop on main
{
.... find where main.QuestionId = sub.QuestionId and it to be added in as a nested object of json type...
Thus the end result SHOULD look like
[{
Active:true,
QuestionId: 3
SubData: [ {
Id: 3,
Name: "TextBox
QuestionId:3
},
{
Id: 4,
Name: "TextBox
QuestionId:3
}],
SalesChannel: "DTD"
}]
// and so on
How can i achieve this?
You want to go through all of the main objects, and assign to them only those results from second query. Use Array.prototype.forEach to go through them all, and Array.prototype.filter to select only appropriate results from secondary query.
firstQueryResult.forEach((firstObject)=>
firstObject.subdata = secondQueryResult.filter((secondObject)=>
secondObject.QuestionId === firstObject.QuestionId))
BTW, this has nothing to do with angularjs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach