JavaScript Multidimensional Array - Object Linking - javascript

I am working with javascript multidimensional array.
Here is the scenario:-
I have a educational institution where user can take classes from any subject. Subjects are not fixed it could be vary. Now there is exam day so suppose there is PHP Lang faculty who will enter his subject name then student name and then marks. If student is enrolled himself for more then 1 subject so its marks will listed in same row.
for example Mr. Anand has enrolled for PHP and HTML and Mr. Deep has enrolled himself for Php only.
Additionally I also want to show minimum and maximum marks as well.
So on result day result card will
Name\Subject | PHP | HTML | Java
--------------------------------------
Anand | 80 | 60 | --
Deep | 70 | -- | --
Sachin | 55 | 56 | 45
so on ... | -- | -- | 80
--------------------------------------
Min Marks | 70 | 56 | 45
Max Mark | 80 | 60 | 80
I have created a multidimensional array but unable to reproduce code as per visual. I think I am doing something wrong.
Below is the code which I have created as of now :-
var data = [
["HTML", [{
"name": "Anand",
"marks": 90
}, {
"name": "Deep",
"marks": 79
}, {
"name": "Raman",
"marks": 34
}]],
["Php", [{
"name": "Anand",
"marks": 90
}, {
"name": "Ekam",
"marks": 40
}]]
]
for (var i = 0; i < data.length; i++) {
document.write("<h2> " + data[i][0] + " </h2>");
var secondLevelData = data[i][1],
secondLen = secondLevelData.length;
for (var j = 0; j < secondLen; j++) {
document.write(secondLevelData[j].name + " -- " + secondLevelData[j].marks + " <br/>");
}
}
Please help me to get the desired result. I am also working on it.
Thanks for your help!!

By changing the JSON we can achieve this. Also added jQuery and underscore libraries for DOM and array manipulations
JS Fiddle Link : https://jsfiddle.net/8Lb7x01u/3/
var data = [
{
"name": "Anand",
"score": [
{
"subject": "HTML",
"marks": 90
},
{
"subject": "Php",
"marks": 90
}
]
},
{
"name": "Deep",
"score": [
{
"subject": "HTML",
"marks": 79
}
]
},
{
"name": "Raman",
"score": [
{
"subject": "HTML",
"marks": 34
}
]
},
{
"name": "Ekam",
"score": [
{
"subject": "Php",
"marks": 40
}
]
}
];
var allScores = _.pluck(data,"score");
var allSubjects = _.groupBy(_.flatten(allScores),"subject");
var allStudents = _.pluck(data,"name");
var headerRow = $("<tr></tr>");
$("<th></th>").html("Name\\Subject").appendTo(headerRow);
for(var subject in allSubjects){
$("<th></th>").html(subject).appendTo(headerRow);
}
headerRow.appendTo(".scoreCard");
for(var i=0;i<allScores.length;i++){
var individualScores = _.groupBy(allScores[i],"subject");
var tr = $("<tr></tr>");
$("<td></td>").html(allStudents[i]).appendTo(tr);
for(var subject in allSubjects)
{
if(individualScores[subject]){
$("<td></td>").html(individualScores[subject][0].marks).appendTo(tr);
}else
{
$("<td></td>").html("...").appendTo(tr);
}
}
tr.appendTo(".scoreCard tbody")
}
renderMaxMin("max");
renderMaxMin("min");
function renderMaxMin(param){
var footerRow = $("<tr></tr>");
$("<td></td>").html(param+" marks").appendTo(footerRow);
for(var subject in allSubjects){
var marks = _.pluck(allSubjects[subject],"marks");
var value =(param === "max") ? _.max(marks) : _.min(marks);
$("<td></td>").html(value).appendTo(footerRow);
}
footerRow.appendTo(".scoreCard tfoot")
}

You are not using the markup in the right manner. You should form the correct markup first, in this case it would be tables.
Also, the way you are storing data could be improved by using associative arrays. It will help you to manage it and use it better as the size of data grows. Here is how you can do that :
var data = [{'HTML' :
[{"name":"Anand","marks":90,
{"name":"Deep","marks": 79},
{"name":"Raman","marks": 34}]
}],
{'PHP' :
[{"name":"Anand","marks": 90},
{"name":"Ekam","marks": 40}]
}]]

Related

calculating total values from a JSON data in jsreport using JavaScript

I am new to jsreport. I have the following data and trying to calculate total salaries,
{
"company": [{
"Remy": {
"age": 32,
"employer": "emp1",
"salary": 20000
},
"Piet": {
"age": 35,
"employer": "emp2",
"salary": 50000
},
"Thando": {
"age": 32,
"employer": "emp3",
"salary": 20000
},
"Greg": {
"age": 33,
"employer": "emp4",
"salary": 70000
}
}]
}
I tried using the following code but I keep getting an error that company.forEach is not a function
function total(company) {
var sum = 0
company.forEach(function (i) {
sum += i.salary
})
return sum
}
I am getting the following error.
Report "Issue" render failed.
Error when evaluating engine handlebars for template anonymous
(because) "total" helper call failed
(because) company.forEach is not a function
(sandbox.js line 14:13)
12 | function total(company) {
13 | var sum = 0
> 14 | company.forEach(function (i) {
| ^
15 | sum += i.salary
16 | })
17 | return sum
This is a good time to use reduce:
const data = {
"company": [{
"Remy": {
"age": 32,
"employer": "emp1",
"salary": 20000
},
"Piet": {
"age": 35,
"employer": "emp2",
"salary": 50000
},
"Thando": {
"age": 32,
"employer": "emp3",
"salary": 20000
},
"Greg": {
"age": 33,
"employer": "emp4",
"salary": 70000
}
}]
}
const salaries = Object.values(data.company[0]).reduce((total, emp) => {
total = emp.salary + total;
return total;
}, 0)
console.log(salaries)
Have a look at the array reduce method for details, but whenever you hear 'calculating' on a list of items reduce isn't a bad option to have a look at to try to solve the issue

Recursively create strings from objects

Hello I have json file:
var jsonData = {
"name": "James",
"age": 22,
"nodes": [
{
"name": "John",
"age": 24,
"nodes": [
{
"name": "Jack",
"age": 65,
"nodes": [
{
"name": "Harry",
"age": 70,
"nodes": []
}
]
},
{
"name": "Joe",
"age": 10,
"nodes": []
}
]
},
{
"name": "Daniel",
"age": 30,
"nodes": []
}
]
}
I need a function that returns output like this:
James 22
James - John 24
James - John - Jack 65
James - John - Jack - Harry 70
James - John - Joe 10
James - Daniel 30
I tried to use recursive function but I don't know how to return output like this one and return age only on last child..
Code:
var json = jsonData;
var prev = [];
function sortData(obj, prev) {
var i = 0;
prev.push(obj.name + " " + obj.age);
console.log(prev);
if (obj.nodes.length > 0) {
while (i < obj.nodes.length) {
sortData(obj.nodes[i], prev);
i++;
prev.pop();
}
}
}
sortData(json, prev);
My function returns output in multiple arrays, so I don't know how to operate with that to return output like that. Will be grateful for any help. Thanks!
You might consider just passing around strings representing the current property path recursively, that way you can just concatenate and pass the value around without worrying about it being mutated. Also, it'll be a lot easier to use array methods like forEach than to use an i variable and manually iterate:
var jsonData={"name":"James","age":22,"nodes":[{"name":"John","age":24,"nodes":[{"name":"Jack","age":65,"nodes":[{"name":"Harry","age":70,"nodes":[]}]},{"name":"Joe","age":10,"nodes":[]}]},{"name":"Daniel","age":30,"nodes":[]}]}
function getAge({ name, age, nodes }, oldPropStr = '') {
const propStr = (oldPropStr ? oldPropStr + ' - ' : '') + name;
console.log(propStr + ' ' + age);
nodes.forEach(node => getAge(node, propStr));
}
getAge(jsonData);
Also, you might note that the current variable name of jsonData is misleading. There's no such thing as a "JSON Object". If you have an object or array, then you have an object or array, full stop. JSON format is a method of representing an object in a string, like const myJSON = '{"foo":"bar"}'. If there are no strings, serialization, or deserialization involved, then JSON is not involved either. Maybe call the variable people or something instead?

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!

How to delete nested json key dynamically?

This is the sample json:
{
"search": {
"facets": {
"author": [
],
"language": [
{
"value": "nep",
"count": 3
},
{
"value": "urd",
"count": 1
}
],
"source": [
{
"value": "West Bengal State Council of Vocational Education & Training",
"count": 175
}
],
"type": [
{
"value": "text",
"count": 175
}
],
}
}
There are several ways to delete key search.facets.source:
delete search.facets.source
delete jsobObj['search']['facets']['source']
var jsonKey = 'source';
JSON.parse(angular.toJson(jsonObj), function (key, value) {
if (key != jsonKey)
return value;
});
Above 1 & 2 are not dynamic, and 3 is one of the way but not a proper way. Because if source is present in another node then it will not work. Please anybody can tell me how to delete it dynamically in any kind of nested key. Because we can not generate sequence of array dynamically in above 2.
Assuming you're starting from this:
let path = 'search.facets.source';
Then the logic is simple: find the search.facets object, then delete obj['source'] on it.
Step one, divide the path into the initial path and trailing property name:
let keys = path.split('.');
let prop = keys.pop();
Find the facets object in your object:
let parent = keys.reduce((obj, key) => obj[key], jsonObj);
Delete the property:
delete parent[prop];
I have found out another solution, it is very easy.
var jsonKey = 'search.facets.source';
eval('delete jsonObj.' + jsonKey + ';');

Creating an multidimensional Array from string (hierarchical data)

I have an Array with this kind of values:
val = [ ['L-2-4-1','john','bla1'],
['L-1-1-26','bohn','bla2'],
['L-2-1','cohn','bla3'],
['L-1-1-05','rohn','bla4'],
['L-1-1','gohn','bla5']
['L-2-3-1','zohn','bla-finally'] ];
The number-sequence is always unique and "0" is never used.
What I'm trying to get would be something like this:
ser = [ [undefined],
[ [undefined],[ ['gohn'],['bla5'] ], [undefined], ... , [ ['bohn'], ['blah2'] ] ],
...
];
The purpose is to be able to access the data like this:
ser[2][4][1][0]; // Array('john','bla1')
ser[1][1][0]; // Array('gohn','bla5')
ser[1][1][26][0]; // Array('bohn','bla2')
and also to loop through all elements.. for instance:
for(var i = 0; i <= ser[1][1].length; i++){ //code }
The main problem I have is that I was not able to set the variables the same way I intend to read them. Because this does NOT work, since I need to declare all arrays separately as arrays (right?)
var ser[1][1][26][0] = ['john','bla1']; // Nop;
I don't know the maximum depth of the tree
Trying to build the arrays from "inside out" or from "right to left" -however it is best described- I always end up overwriting previously set array elements.
Maybe the whole idea is too complicated (or at least not ideal) for the purpose? What would you suggest? I have the feeling I´m trying to do the right thing but the wrong way... Something like organizing marbles on a glass surface. Everything keeps moving around...
Have you considered representing your data in JSON?
It allows for complex structures that are otherwise too confusing to keep in your head. It's like XML meets JavaScript arrays. Rather self-describing and easy to follow. You can read the lengths and sizes of objects easily and it's quite fast. You can use values instead of array positions and re-think the structure of your data.
http://json.org/example.html
Here is a record in JSON:
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
http://labs.adobe.com/technologies/spry/samples/data_region/JSONDataSetSample.html
short and sweet:
var i, j, t, final = [];
for (i = 0; i < val.length; i++) {
t = val[i][0].split('-');
for (j = 1; j < 5; j++) {
t[j] = parseInt(t[j], 10) || 0;
}
final[t[1]] = final[t[1]] || [];
final[t[1]][t[2]] = final[t[1]][t[2]] || [];
final[t[1]][t[2]][t[3]] = final[t[1]][t[2]][t[3]] || [];
final[t[1]][t[2]][t[3]][t[4]] = final[t[1]][t[2]][t[3]][t[4]] || [];
final[t[1]][t[2]][t[3]][t[4]].push(val[i].slice(1));
}
final now has the correct data as you specified...
however, you might want to consider using objects instead of arrays (change all [] to {}) as the random insertion points in arrays lead to series of empty (null) values, the only caveat would be that you'd have to use a for (var key in obj) style loop...
hope this helps -ck
IF YOU NEED DYNAMIC DEPTH
var i, j, t, o, depth = 4, final = [];
for (i = 0; i < val.length; i++) {
t = val[i][0].split('-');
o = final;
for (j = 1; j <= depth; j++) {
t[j] = parseInt(t[j], 10) || 0;
o[t[j]] = o[t[j]] || [];
o = o[t[j]];
}
o.push(val[i].slice(1));
}
now depth is the constant at which the data is stored missing or unparsable "keys" or "indices" depending on how you want to think of them, default to 0
enjoy -ck

Categories