Convert array of paths into a Tree in JavaScript [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 months ago.
Improve this question
Given this input:
const paths = ["src", "src/components", "src/components/index.ts", "src/utils", "src/configuration/config.ts", "another/file.ts"];
I need to create a function or a data structure that returns a Tree with the following structure.
[
{
"id": "src",
"level": 1,
"childrens": [
{
"id": "src/components",
"level": 2,
"childrens": [
{
"id": "src/components/index.ts",
"level": 3,
"childrens": []
}
]
},
{
"id": "src/utils",
"level": 2,
"childrens": []
},
{
"id": "src/configuration",
"level": 2,
"childrens": [
{
"id": "src/configuration/config.ts",
"level": 3,
"childrens": []
}
]
}
]
},
{
"id": "another",
"level": 1,
"childrens": [
{
"id": "another/file.ts",
"level": 2,
"childrens": []
}
]
}
]
I tried everything but I can't make it work, so if anyone can help I would appreciate it a lot.
Thank you.

First, here's the solution based on this answer: https://stackoverflow.com/a/57344801/3807365.
Explanation below.
const paths = ["src", "src/components", "src/components/index.ts", "src/utils", "src/configuration/config.ts", "another/file.ts"];
let agg = {
temp: []
};
paths.forEach(path => {
path.split('/').reduce((agg, part, level, parts) => {
if (!agg[part]) {
agg[part] = {
temp: []
};
agg.temp.push({
id: parts.slice(0, level + 1).join("/"),
level: level + 1,
children: agg[part].temp
})
// console.log(agg)
}
return agg[part];
}, agg)
})
var result = agg.temp;
console.log(result)
.as-console-wrapper {
max-height: 100% !important;
}
Explanation:
Given a path (splitted to parts) and the result which is an empty array []
we are building this kind of object (helper object!):
{
"src" : {
"utils" : {
"file.ts" : {}
},
"components" : {
"file.ts" : {}
}
},
"another": {
"file.ts" : {}
}
}
We do this step by step as we go on each part of the path.
And we do this to each path building this lovely tree.
Simple enough.
But as we do, we are creating arrays in the result object (which is under property temp) - arrays of items of the same level in the format {id, level, children}.
Finally, we ignore this entire helper tree and only return the first level array - which is the result (under property temp).
Once you realize this, you can see the possible error in this method. Can you spot it? What kind of path name will "mess" with the result?

Related

How to get this output from JSON in javascipt ny comparing student_id from mark_details and students_detail?

JSON Object:
{
"students_detail": [
{
"student_id": 1,
"name": "abc",
"roll_number": 10
},
{
"student_id": 2,
"name": "pqr",
"roll_number": 12
}
],
"subject_details": [
{
"subject_id": 1,
"subject_name": "math"
},
{
"subject_id": 2,
"subject_name": "english"
}
],
"exam_details": [
{
"exam_id": 1,
"exam_name": "Prelim"
}
],
"mark_details": [
{
"id": 1,
"exam_id": 1,
"subject_id": 1,
"student_id": 1,
"mark": 51
},
{
"id": 2,
"exam_id": 1,
"subject_id": 2,
"student_id": 2,
"mark": 61
}
]
}
Ouptut:
{
"student_mark_details": [
{
"abc": {
"roll_number": 10,
"Prelim": [
{
"subject_name": "math",
"mark": 51
}
]
},
"pqr": {
"roll_number": 12,
"Prelim": [
{
"subject_name": "english",
"mark": 61
}
]
}
}
]
}
i tried using loops and accesing student_id in both object and comparing them but code gets too messy and complex,is there any way i can use map() or filter() in this or any other method.
i have no idea where to start,my brain is fried i know im asking lot but help will be appreciated (any link/source where i can learn this is fine too)
Your output object really has a weird format: student_mark_details is an array of size 1 that contains an object that has all your students in it. Anyway, this should give you what you need. It is a format that you find often because it is a system with primary key and secondary key used a lot in databases.
The key to manage that is to start with what is at the core of what you are looking for (here, you want to describe students, so you should start from there), and then navigate the informations you need by using the primary/secondary keys. In JS, you can use the find() function in the case where one secondary key can be linked only to one primary key (ex: one mark is linked to one exam), and the filter() function when a secondary key can be linked to multiple secondary keys (ex: a student is linked to many grades).
I am not sure if this is 100% what you need because there are maybe some rules that are not shown in your example, but it solves the problem you submitted here. You might have to test it and change it depending of those rules. I don't know what your level is so I commented a lot
const data = {
"students_detail": [
{
"student_id": 1,
"name": "abc",
"roll_number": 10
},
{
"student_id": 2,
"name": "pqr",
"roll_number": 12
}
],
"subject_details": [
{
"subject_id": 1,
"subject_name": "math"
},
{
"subject_id": 2,
"subject_name": "english"
}
],
"exam_details": [
{
"exam_id": 1,
"exam_name": "Prelim"
}
],
"mark_details": [
{
"id": 1,
"exam_id": 1,
"subject_id": 1,
"student_id": 1,
"mark": 51
},
{
"id": 2,
"exam_id": 1,
"subject_id": 2,
"student_id": 2,
"mark": 61
}
]
}
function format(data) {
const output = {
"student_mark_details": [{}]
};
//I start by looping over the students_detail because in the output we want a sumary by student
data.students_detail.forEach(student => {
//Initialization of an object for a particular student
const individualStudentOutput = {}
const studentId = student.student_id;
const studentName = student.name;
//The rollNumber is easy to get
individualStudentOutput.roll_number = student.roll_number;
//We then want to find the exams that are linked to our student. We do not have that link directly, but we know that our student is linked to some marks
//Finds all the marks that correspond to the student
const studentMarkDetails = data.mark_details.filter(mark => mark.id === studentId);
studentMarkDetails.forEach(individualMark => {
//Finds the exam that corresponds to our mark
const examDetail = data.exam_details.find(exam => individualMark.exam_id === exam.exam_id);
//Finds the subject that corresponds to our mark
const subjectDetail = data.subject_details.find(subject => individualMark.subject_id === subject.subject_id);
//We then create a grade that we will add to our exam
const grade = {
subject_name: subjectDetail.subject_name,
mark: individualMark.mark
}
//We then want to add our grade to our exam, but we don't know if our output has already have an array to represent our exam
//So in the case where it does not exist, we create one
if (!individualStudentOutput[examDetail.exam_name]) {
individualStudentOutput[examDetail.exam_name] = [];
}
//We then add our grade to the exam
individualStudentOutput[examDetail.exam_name].push(grade);
});
//Now that we have finished our individual output for a student, we add it to our object
output.student_mark_details[0][studentName] = individualStudentOutput;
})
return output;
}
console.log(JSON.stringify(format(data)))

How to analyze/count an array of objects in Javascript

Stack Overflow! This is my very first.
So, say for example I have the following array:
[
{
"question1": "Apple",
"question2": 5,
"question3": "Item 1"
},
{
"question1": "Apple",
"question2": 4,
"question3": "Item 2"
},
{
"question1": "Orange",
"question2": 4,
"question3": "Item 2"
}
]
Each object represents a respondent's answers to each question from a survey, which means the array above has a total of 3 responses.
What I want is to count the answers of each question, like how many in a multiple choice question chose X answer and so on.
The following output should look like this for a single question:
[
{
"answer": "Apple",
"count": 2,
},
{
"answer": "Orange",
"count": 1,
}
]
Which means according to the example above I'll need total of 3 arrays (because total 3 questions) of counted answers.
Is there any way to achieve this? My goal here is to use ChartJS in React to display charts of the responses of each question.
Final output for a single chart (of a single question, say question1):
[
{
"answer": "Apple",
"count": 2,
},
{
"answer": "Orange",
"count": 1,
}
]
This outputs an array of arrays of objects, instead of multiple array variables of objects. Since JavaScript objects preserve insertion order, you don't need to worry about the questions being out of order, assuming they're already in the proper order.
const data = [{question1:"Apple",question2:5,question3:"Item 1"},{question1:"Apple",question2:4,question3:"Item 2"},{question1:"Orange",question2:4,question3:"Item 2"}];
const newData = Object.values(data.reduce((acc, qna) => {
for (const [question, answer] of Object.entries(qna)) {
acc[question] = acc[question] ?? {};
acc[question][answer] = (acc[question][answer] ?? 0) + 1;
}
return acc;
}, {}))
.map((answerCount) => Object.entries(answerCount)
.map(([answer, count]) => ({ answer, count }))
);
console.log(newData);

How do I verify and count the presence of specific data in an associative array?

I have a question about manipulating data in an associative array.
What I want to do
I want to verify if an order exists in sellingItems.
Background(why?)
I want to check if there is an order to return the number of products in stock as a response.
Question
I want to check if a specific data (order) exists in an associative array and calculate the inventory count.
public calculateStockQuantity(itemInstances) {
const stockQuantity = //We want to count the number of items in stock. In this case, we want it to be 2 (calculated based on whether the data exists in sellingItem.order or not).)
  return stockQuantity;
}
Associative array of targets
//There are three itemInstances for one product because the number of products sold is three.
itemInstances =
[
{
"id": "1",
"sellingItem": [
{
"id": 1,
"price": 3000,
"orderedItem": [
{
"id": 1
              "ordered_at": "2021-04-01 10:00:00"
}
]
}
]
},
{
"id": "2",
"sellingItem": [
{
"id": 2,
"price": 3000,
"orderedItem": []
}
]
},
{
"id": "2",
"sellingItem": [
{
"id": 2,
"price": 3000,
"orderedItem": []
}
]
}
]
Sorry for asking like a newbie.
Please check if this is something you are looking for, assuming if orderedItem array is empty then that sellingItem will be counted as in stock
let count = itemInstances.filter(({sellingItem : [{ orderedItem }]}) => orderedItem.length === 0).length;
console.log(count); //return 2 based on question data

How does one filter json after type?

So, I have a json which looks a little bit like this:
{
"data": {
"user": {
"edge_followed_by": {
"count": 22,
"page_info": {
"has_next_page": true,
"end_cursor": "Base64"
},
"edges": [
{
"node": {
"id": "id",
"username": "Username",
"full_name": "played",
"profile_pic_url": "URL"
}
}
]
}
}
}
}
And I want to filter out the username. How do I do that?
You could retrieve it with a map function there
const dataSample = {
"data": {
"user": {
"edge_followed_by": {
"count": 22,
"page_info": {
"has_next_page": true,
"end_cursor": "Base64"
},
"edges": [
{
"node": {
"id": "id",
"username": "Username",
"full_name": "played",
"profile_pic_url": "URL"
}
}
]
}
}
}
}
const getUsernames = data => {
return data.data.user.edge_followed_by.edges.map(e => e.node.username)
}
console.log(getUsernames(dataSample))
:)
This can be a little tricky to understand from the question first of all.
My interpretation of this is you want to extract a username
"Filtering" also could mean you want to remove something from a collection that passes a condition (or test) of some kind.
For example: Removing all even numbers from an array
let x = [1, 2, 4, 5, 6];
let filtered = x.filter(value => value % 2 === 0);
Now, I've looked at your json, and I think the best point of targeting this is by getting the "edges" property and running it through an inbuilt function like map; that could be used to get usernames. The edges is an array as well.
data.user.edge_followed_by.edges.map(userObject => userObject.username)
That would effectively remove all usernames from the edges if your tech stack of choice was javascript.
I got this info from a post like: https://coderin90.com/blog/2019/map-js

How order a JSON alphabetically in javascript, like this? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I can ordering a-z using the .sort() method in javascript, but I would get a JSON like this: (With a "A-Z" index containing the result)
data: {
"A": [
{
"name": "Anh Tuan Nguyen",
"age": 28
},
{
"name": "An Nguyen",
"age": 20
},
],
"Z": [
{
"name": "Zue Dang",
"age": 22
},
{
"name": "Zoom Jane",
"age": 30
},
]
}
var names = [{name:"a1"},{name:"a2"},{name:"b1"},{name:"b2"}.....];
var data = {};
for (var i = 0; i < names.length; i++) {
var n = names[i].name.subStr(0,1);
if (data[n] == null)
data[n] = [];
data[n].push(names[i]);
}
There is no way to sort a JSON data structure, however, we can do it by using the following process:
Get your data keys with Object.keys(myResults.data)
Sort you keys
Create a reduce function to transform your ordered keys into an ordered object
The snippet is here, I hope it helps:
var myResults = {
data: {
C: [
{
"name": "Kevin Doe",
"age": 22
}
],
A: [
{
"name": "Alex Doe",
"age": 31,
}
],
B: [
{
"name": "Boris Doe",
"age": 22
},
{
"name": "Birdo Doe",
"age": 30
},
]
}
};
var originalData = myResults.data;
// 1. get the keys
var dataKeys = Object.keys(originalData);
// 2. sort the keys
var sortedKeys = dataKeys.sort();
// 3. create the object again
var orderedData = sortedKeys.reduce(function(result, key) {
return Object.assign(
{},
result,
{ [key]: myResults.data[key] }
);
}, {});
document.getElementById('original').innerHTML = JSON.stringify(originalData);
document.getElementById('sorted').innerHTML = JSON.stringify(orderedData);
h3 {
margin: 0;
}
code {
display: block;
margin-bottom: 15px;
padding: 10px;
background-color: #f9f9f9;
}
<h3>Original Data</h3>
<code id="original"></code>
<h3>Ordered Data</h3>
<code id="sorted"></code>
JavaScript objects are not ordered. If you want to iterate over an object's properties, you can sort the keys and then retrieve your values:
const result = {
data: {
Z: [],
F: [],
A: [],
D: []
}
};
Object
.keys(result.data)
.sort()
.map(key => console.log(key, result.data[key]));
UPDATE:
Exist a JavaScript library that make It possible: Lodash Utilities (https://lodash.com/docs/4.17.4). Contain methods for .sort() JSON (no Arrays) and a method to obtain the JSON for I asked in this question. I only did this:
//First, order my JSON alphabetically with _.sortBy method (I can even order by a nested property in my JSON)
var order = _.sortBy(require('./names'), function (el) { return el.name });
//Second, I group my order result by the first letter of my property 'name' in my JSON
var list = _.groupBy(order, (b) => b.name[0].toUpperCase());
This is my input:
[
{"name":"Mark"},
{"name":"Jul"},
{"name":"Alicia"},
]
This is my output:
[
"A": [
{
"name": "Alicia"
}
],
"J": [
{
"name": "Jul"
},
],
"M": [
{
"name": "Mark"
},
]
I hope this help to somebody!

Categories