I have an array of object with looks like recursive until level 3.
const mainArr = [{
children: [{
children: [{
children: [{
children: [{}],
level: 3
}],
level: 2
}],
level: 1
}],
level: 0
}]
I want to create an array with Level 2 object that have child items
Here is my way to achieve what i want but it looks like a bad way.
reasons = [
...[...data.map((level0) => level0.children)]
.flat()
.map((level1) => level1.children)
.flat(),
].filter((level2) => level2.children.length);
I want to improve code block that i give in above
(edited)
Output
[
{
"children": [
{
"name": "Reason",
"level": 3
}
],
"level": 2
},
{
"children": [
{
"name": "Reason2",
"level": 3
}
],
"level": 2
}
]
One possible way to improve the code block you provided is by using the flatMap method instead of map and flat. flatMap applies a function to each element of an array and flattens the result into a new array, which can simplify your code. Here's an example implementation:
const result = mainArr.flatMap(level0 =>
level0.children.flatMap(level1 =>
level1.children.filter(level2 =>
level2.children && level2.children.length > 0 && level2.level === 2
)
)
);
In this code block, flatMap is used to iterate over the first level of the main array and the second level of the children arrays. Then, filter is used to keep only the level 2 objects that have child items. Note that the filter condition also checks whether level2.children is not null or undefined before checking its length to avoid errors.
This implementation should give you the same output as your code block but in a more concise way.
Related
I have a question about creating JavaScript arrays. Here's what I want to do.
I have two arrays. Each array has object(s) in them.
The first array has exactly 5 objects, each with a key/value pair (id/name). This array will ALWAYS have 5 objects.
Here's what it looks like...
[
{
"id": 1,
"name": "AnalyticalAdmin"
},
{
"id": 2,
"name": "Analyst"
},
{
"id": 4,
"name": "AdminReviewer"
},
{
"id": 5,
"name": "SystemAdministrator"
},
{
"id": 6,
"name": "CaseworkSTRTechLeader"
}
]
The second array will have either...
no objects,
4 or less objects,
exactly 5 objects.
In the example below, the second array only has one of the 5 objects in the first array...
[
{
"id": 4,
"name": "AdminReviewer"
}
]
I need to create a third array that has exactly 5 boolean values that are determined by comparing the first two arrays.
For example, based on the first two arrays above, the third array would be...
[false, false, true, false, false]
The reason the third array would look like this is because "AdminReviewer" is the third object in the first array, so the third boolean value in the third array would be true (since it's a match).
But because the first, second, fourth, and fifth objects in the first array do not exist in the second array, their boolean equivalent in the third array would be false.
To accomplish this, I know I need to either do a compare function on the first two arrays to create the third array (of booleans) or I need to run a for loop on the first array, comparing it to the second array to create the third array (of booleans).
Can anyone help me with this?
This could be done as follows:
const filterStrings = filterArray.map(o => JSON.stringify(o));
const result = baseArray.map(o => filterStrings.includes(JSON.stringify(o)));
Please take a look at below runnable code and see how it works.
const baseArray = [
{
"id": 1,
"name": "AnalyticalAdmin"
},
{
"id": 2,
"name": "Analyst"
},
{
"id": 4,
"name": "AdminReviewer"
},
{
"id": 5,
"name": "SystemAdministrator"
},
{
"id": 6,
"name": "CaseworkSTRTechLeader"
}
];
const filterArray = [
{
"id": 4,
"name": "AdminReviewer"
}
];
const filterStrings = filterArray.map(o => JSON.stringify(o));
const result = baseArray.map(o => filterStrings.includes(JSON.stringify(o)));
console.log(result);
This question already has answers here:
Group by array and add field and sub array in main array
(8 answers)
Closed 1 year ago.
As a newbie, I'm looking for the best approach to achieve the below:
Here is the Array I get from my DB query that contains a left join on the "class" table
[
{"legnumber":1,
"classcode" : "J"},
{"legnumber":1,
"classcode" : "Y"},
{"legnumber":2,
"classcode" : "J"}
]
And I would like to get something like this:
{
"legs": [
{
"legnumber" : 1,
"classes" : [
{"classcode" : "J"},
{"classcode" : "Y"}
]
},
{
"legnumber" : 2,
"classes" : [
{"classcode" : "J"}
]
}
]
}
Thanks a lot for your suggestions.
I'm using Sequelize in this project but I'm writing raw queries as I find it more convenient for my DB model.
Regards,
Nico
Hassan's answer is the more concise way to handle this, but here is a more verbose option to help understand what's happening:
const queryResults = [
{ legnumber: 1, classcode: 'J' },
{ legnumber: 1, classcode: 'Y' },
{ legnumber: 2, classcode: 'J' },
]
// create an object to store the transformed results
const transformedResults = {
legs: [],
}
// loop through each item in the queryResult array
for (const result of queryResults) {
// try to find an existing leg tha matches the current leg number
let leg = transformedResults.legs.find((leg) => leg.legnumber === result.legnumber)
// if it doesn't exist then create it and add it to the transformed results
if (!leg) {
leg = {
legnumber: result.legnumber,
classes: [],
}
transformedResults.legs.push(leg)
}
// push the classcode
leg.classes.push({ classcode: result.classcode })
}
console.log(transformedResults)
You can group your array items based on legnumber using array#reduce and then get all the values to create your result using Object.values().
const arr = [ {"legnumber":1, "classcode" : "J"}, {"legnumber":1, "classcode" : "Y"}, {"legnumber":2, "classcode" : "J"} ],
output = arr.reduce((r, {legnumber, classcode}) => {
r[legnumber] ??= {legnumber, classes: []};
r[legnumber].classes.push({classcode});
return r;
},{}),
result = {legs: Object.values(output)};
console.log(result);
I'm trying to find min and max values in tree like object using recursion, but I don't actualy understand how to find this values. Also my function must be pure and I can't use loops or forEach. Only map, reduce, filter are avalaible. So this is how my data looks like:
const tree = {
children: [
{
children: [
{
children: [],
values: [15.667786122807836]
}
],
values: [35.77483035532576, 1.056418140526505]
},
{
children: [
{
children: [
{
children: [],
values: [67.83058067285563]
}
],
values: [98.89823527559626]
}
],
values: [51.49890385802418, 41.85766285823911]
},
],
values: [6.852857017193847, 28.110428400306265, 51.385186145220494]};
I'm trying to do something like this:
const min = graph => {
if (!graph.children.length && !graph.values.length) return;
if (!graph.children.length && graph.values.length) {
return Math.min(...graph.values);
}
return graph.children.map(el => {
const minValue = Math.min(...el.values);
min(el);
return minValue;
});
};
But this not work well. So guys can anybody explain how the callstack works, maybe give me some good examples, and explain how to solve my problem. Thanks for the help and sorry for the bad English). Oh, and also)) how to get the distance between two nodes in the different depth level?
Usually with homework questions, I would prompt for more dialog with the OP, but as this already has a working, accepted answer, I'll just add a simpler one:
const min = ({values = [], children = []}) =>
Math .min (...values, ... children .map (min))
const tree = {children: [{children: [{children: [], values: [15.667786122807836]}], values: [35.77483035532576, 1.056418140526505]}, {children: [{children: [{children: [], values: [67.83058067285563]}], values: [98.89823527559626]}], values: [51.49890385802418, 41.85766285823911]}, ], values: [6.852857017193847, 28.110428400306265, 51.385186145220494]};
console .log (min (tree))
We just use Math.min, spreading the current values and the results of recursive calls to each of its children into arguments to it. We default both values and children to empty arrays in case either is missing at any node.
Clearly max is a trivial change to this.
I'm not a JS programmer but am always looking to practice. Here's what I came up with:
const tree = {
children: [{
children: [{
children: [],
values: [15.667786122807836]
}],
values: [35.77483035532576, 1.056418140526505]
},
{
children: [{
children: [{
children: [],
values: [67.83058067285563]
}],
values: [98.89823527559626]
}],
values: [51.49890385802418, 41.85766285823911]
},
],
values: [6.852857017193847, 28.110428400306265, 51.385186145220494]
};
function treeMin(graph) {
if (graph.children.length == 0) return Math.min(...graph.values);
return Math.min(...graph.values,
graph.children.reduce((prev, cur) =>
Math.min(prev, treeMin(cur)), Number.MAX_SAFE_INTEGER
));
}
console.log(treeMin(tree));
I gave the function a name to make the recursive calls. The first thing it does is check if there are no children. If not, it just returns the min of the values.
If there are children, return the min of values and the result of calling reduce on the children. Inside reduce, the recursive calls are made.
Note: it does not handle the case where values is empty. This can be easily added.
I want to loop through 600+ array items in an object and find one particular item based on certain criteria. The array in the object is called "operations" and its items are arrays themselves.
My goal is to get the index of operation's array item which has the deeply nested string "Go".
In the sample below this would be the first element. My problem is that I can check if an array element contains "call" and "draw" but I don't know how to test for the nested dictionary "foobar". I only have basic JavaScript available, no special libraries.
let json = {
"head": {},
"operations": [
[
"call",
"w40",
"draw",
{
"parent": "w39",
"style": [
"PUSH"
],
"index": 0,
"text": "Modify"
}
],
[
"call",
"w83.gc",
"draw",
{
"foobar": [
["beginPath"],
[
"rect",
0,
0,
245,
80
],
["fill"],
[
"fillText",
"Go",
123,
24
],
[
"drawImage",
"rwt-resources/c8af.png",
]
]
}
],
[
"create",
"w39",
"rwt.widgets.Menu",
{
"parent": "w35",
"style": [
"POP_UP"
]
}
],
[
"call",
"w39",
"draw",
{
"parent": "w35",
"style": [
"POP_UP"
]
}
]
]
};
let index = "";
let operationList = json.operations;
for (i = 0; i < operationList.length; i++) {
if (operationList[i].includes('call') && operationList[i].includes('draw')) //missing another check if the dictionary "foobar" exists in this element )
{
index = i;
}
}
document.write(index)
I'll preface by saying that this data structure is going to be tough to manage in general. I would suggest a scheme for where an operation is an object with well defined properties, rather than just an "array of stuff".
That said, you can use recursion to search the array.
If any value in the array is another array, continue with the next level of recursion
If any value is an object, search its values
const isPlainObject = require('is-plain-object');
const containsTerm = (value, term) => {
// if value is an object, search its values
if (isPlainObject(value)) {
value = Object.values(value);
}
// if value is an array, search within it
if (Array.isArray(value)) {
return value.find((element) => {
return containsTerm(element, term);
});
}
// otherwise, value is a primitive, so check if it matches
return value === term;
};
const index = object.operations.findIndex((operation) => {
return containsTerm(operation, 'Go');
});
I have an object that has unique keys and each key holds an object:
var object = { 'a': {
source: '5279edf0-cd7f-11e3-af07-59475a41e2e9',
target: 'f6b3faa1-ad86-11e3-9409-3dbc47429e9f',
id: [ 'bf504d02-81e2-4a92-9c5c-8101943dc36d' ],
edge_context: [ 'small' ],
statement_id: [ '09b05bc0-20ab-11e9-a5b3-9fb3da66a7cb' ],
weight: 2
},
'b': {
source: '5279edf1-cd7f-11e3-af07-59475a41e2e9',
target: 'f6b3faa1-ad86-11e3-9409-3dbc47429e9f',
id: [ 'de769846-9145-40f8-ab2d-91c0d9b82b27',
'd5723929-71a0-4dfe-bf03-94d43e358145' ],
edge_context: [ 'small' ],
statement_id:
[ '09b05bc0-20ab-11e9-a5b3-9fb3da66a7cb',
'62671510-20ab-11e9-8cbf-ef11fdb08712' ],
weight: 6
}
}
var newArray = [];
for (let item of object) {
newArray(item);
}
console.log(newArray);
I want to map it to another array where the keys will be in a sequence 0, 1, 2 etc as the usual array
I tried to use this function above but it's not working saying "object is not iterable" so how to iterate the object?
Maybe:
const mappedObject = Object.keys(object).map(
k => object[k]
)
As others have pointed out, change the structure. It could be in the following way (you will obtain an array of objects, which you will be able to access using indexes like 0, 1, 2, etc):
var objt = [
{"a": {
"source": "5279edf0-cd7f-11e3-af07-59475a41e2e9",
"target": "f6b3faa1-ad86-11e3-9409-3dbc47429e9f",
"id": [ "bf504d02-81e2-4a92-9c5c-8101943dc36d" ],
"edge_context": [ "small" ],
"statement_id": [ "09b05bc0-20ab-11e9-a5b3-9fb3da66a7cb" ],
"weight": 2
}
},
{"b": {
"source": "5279edf1-cd7f-11e3-af07-59475a41e2e9",
"target": "f6b3faa1-ad86-11e3-9409-3dbc47429e9f",
"id": [ "de769846-9145-40f8-ab2d-91c0d9b82b27",
"d5723929-71a0-4dfe-bf03-94d43e358145" ],
"edge_context": [ "small" ],
"statement_id":
[ "09b05bc0-20ab-11e9-a5b3-9fb3da66a7cb",
"62671510-20ab-11e9-8cbf-ef11fdb08712" ],
"weight": 6
}
}
];
var newArray = objt.map(element => {
const firstProperty = Object.keys(element)[0];
let objectInfo = element[firstProperty];
console.log(objectInfo);
return objectInfo;
});
console.log(newArray);
What happens here is, the only field of each object is not named the same (in one object is "a", the next one is "b", and so on) so we need to figure out to get the only property of each object in the initial array, which contains the information you need to put in another array. For doing this. Object.keys() returns you an array of the properties of an object. Considering the scenario in which we only have one property per object, we get it using Object.keys(element)[0].
Finally, we just use .map() to generate a new array.
I would use Object.values(object) but it's not supported by IE (there is a polyfill for that). Or would use Object.getOwnPropertyNames (which is supported by IE) to convert the keys to an array and map the array to another which containing the values.
var newArray = Object.getOwnPropertyNames(object).map(key => object[key])