Convert JS array to objects - javascript

I have a problem with the correct converting array to the form what I need from a graph plugin. I have a JSON which looks like below, from this file I have to count how many titles I have (see pic. 1). Hope you will understand from the pictures.
[
{
"name": "Mike Frost",
"title": "value_1",
"gender": "Male"
},
{
"name": "Hans Karl",
"title": "value_6",
"gender": "Male"
},
{
"name": "Kelly Clarkson",
"title": "value_3",
"gender": "Female"
},
...
]
This what I've got so far:
This what I need:
There is my script which counts values from JSON.
var employeeData = require('json!../path/to/json.json');
var obj = [];
for (var i = 0, j = employeeData.length; i < j; i++) {
if (obj[employeeData[i]['title']]) {
obj[employeeData[i]['title']]++;
}
else {
obj[employeeData[i]['title']] = 1;
}
}

One convenient way to do this is with a map (either a real Map if you're using ES2015, or an object we're using as a map if you're using ES5 or earlier). You build a new array and also keep track of the array entries in the map keyed by the value_X value:
var json = '[' +
' {' +
' "name": "Mike Frost",' +
' "title": "value_1",' +
' "gender": "Male"' +
' },' +
' {' +
' "name": "Hans Karl",' +
' "title": "value_6",' +
' "gender": "Male"' +
' },' +
' {' +
' "name": "Another Six",' +
' "title": "value_6",' +
' "gender": "Male"' +
' },' +
' {' +
' "name": "Kelly Clarkson",' +
' "title": "value_3",' +
' "gender": "Female"' +
' },' +
' {' +
' "name": "Another 3",' +
' "title": "value_3",' +
' "gender": "Female"' +
' },' +
' {' +
' "name": "Yet Another 3",' +
' "title": "value_3",' +
' "gender": "Female"' +
' }' +
']';
// Parse the JSON
var data = JSON.parse(json);
// The new array we'll build
var newArray = [];
// Our "map"
var map = Object.create(null);
// Loop the parsed data
data.forEach(function(entry) {
// Get the existing new entry if any
var mapEntry = map[entry.title];
if (mapEntry) {
// We have one, increase its `value`
++mapEntry.value;
} else {
// There isn't one, create it with a count of 1
// and save it to the array
mapEntry = map[entry.title] = {
label: entry.title,
value: 1
};
newArray.push(mapEntry);
}
});
// Done
console.log(newArray);
That can be written much more concisely, but I wanted to call out the individual parts of what I was doing.
In ES2015+:
const json = `[
{
"name": "Mike Frost",
"title": "value_1",
"gender": "Male"
},
{
"name": "Hans Karl",
"title": "value_6",
"gender": "Male"
},
{
"name": "Another Six",
"title": "value_6",
"gender": "Male"
},
{
"name": "Kelly Clarkson",
"title": "value_3",
"gender": "Female"
},
{
"name": "Another 3",
"title": "value_3",
"gender": "Female"
},
{
"name": "Yet Another 3",
"title": "value_3",
"gender": "Female"
}
]`;
// Parse the JSON
const data = JSON.parse(json);
// The new array we'll build
const newArray = [];
// Our map
const map = new Map();
// Loop the parsed data
data.forEach(entry => {
// Get the existing new entry if any
let mapEntry = map.get(entry.title);
if (mapEntry) {
// We have one, increase its `value`
++mapEntry.value;
} else {
// There isn't one, create it with a count of 1
// and save it to the array
mapEntry = {
label: entry.title,
value: 1
};
map.set(entry.title, mapEntry);
newArray.push(mapEntry);
}
});
// Done
console.log(newArray);

You can use Array.prototype.reduce and a hash table to group the data - see demo below:
var object=[{name:"Mike Frost",title:"value_1",gender:"Male"},{name:"Hans Karl",title:"value_6",gender:"Male"},{name:"Kelly Clarkson",title:"value_3",gender:"Female"},{name:"Mike Frost",title:"value_1",gender:"Male"},{name:"Hans Karl",title:"value_6",gender:"Male"}];
var result = object.reduce(function(hash){
return function(prev, curr){
if(hash[curr.title])
hash[curr.title].value++;
else {
hash[curr.title] = {label: curr.title, value: 1};
prev.push(hash[curr.title]);
}
return prev;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}

You could iterate the array and count the occurence of the same titles.
var data = [{ "name": "Mike Frost", "title": "value_1", "gender": "Male" }, { "name": "Hans Karl", "title": "value_6", "gender": "Male" }, { "name": "Kelly Clarkson", "title": "value_3", "gender": "Female" }, { "name": "Kelly Clarkson", "title": "value_3", "gender": "Female" }, ],
result = data.reduce(function (hash) {
return function (r, a) {
if (!hash[a.title]) {
hash[a.title] = { label: a.title, value: 0 };
r.push(hash[a.title]);
}
hash[a.title].value++;
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6 with Map
var data = [{ "name": "Mike Frost", "title": "value_1", "gender": "Male" }, { "name": "Hans Karl", "title": "value_6", "gender": "Male" }, { "name": "Kelly Clarkson", "title": "value_3", "gender": "Female" }, { "name": "Kelly Clarkson", "title": "value_3", "gender": "Female" }, ],
result = data.reduce(
(map =>
(r, a) =>
(!map.has(a.title) && map.set(a.title, r[r.push({ label: a.title, value: 0 }) - 1]), map.get(a.title).value++, r)
)(new Map), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Can't seem to reference data in a complex JSON file, probably just my syntax

I am a noob so please forgive me. I have the following JSON file:
`{ "Series": {"Next":
[ { "Name": "Cheese", "Price" : 2.50, "Location": "Refrigerated foods"},
{ "Name": "Crisps", "Price" : 3, "Location": "the Snack isle"},
{ "Name": "Pizza", "Price" : 4, "Location": "Refrigerated foods"},
{ "Name": "Chocolate", "Price" : 1.50, "Location": "the Snack isle"},
{ "Name": "Self-raising flour", "Price" : 1.50, "Location": "Home baking"},
{ "Name": "Ground almonds", "Price" : 3, "Location": "Home baking"} ]}`
I'm trying to reference the Name, Location and Price but it's now working. Here is the JavaScript code I am using:
.then(function(json) {
for(var i = 0; i < json.Next.length; i++) {
var listItem = document.createElement('li_prod');
listItem.innerHTML = '<strong_prod>' + json.Next[i].Name + '</strong_prod>';
listItem.innerHTML +=' can be found in ' + json.Next[i].Location + '.';
listItem.innerHTML +=' Cost: <strong_prod>£' + json.Next[i].Price + '</strong_prod>';
myList.appendChild(listItem);
}
that code is not picking up the Name, Location or price. How can I reference the data? Something like json.Series.Next[i].Name?
with the structure of your object it's more json.Series.Next instead of json.Next
var json = {
"Series": {
"Next":
[{
"Name": "Cheese",
"Price": 2.50,
"Location": "Refrigerated foods"
},
{
"Name": "Crisps",
"Price": 3,
"Location": "the Snack isle"
},
{
"Name": "Pizza",
"Price": 4,
"Location": "Refrigerated foods"
},
{
"Name": "Chocolate",
"Price": 1.50,
"Location": "the Snack isle"
},
{
"Name": "Self-raising flour",
"Price": 1.50,
"Location": "Home baking"
},
{
"Name": "Ground almonds",
"Price": 3,
"Location": "Home baking"
}
]
}
}
var myList = document.getElementById('my-list');
for (var i = 0; i < json.Series.Next.length; i++) {
var listItem = document.createElement('li_prod');
listItem.innerHTML = '<strong_prod>' + json.Series.Next[i].Name + '</strong_prod>';
listItem.innerHTML += ' can be found in ' + json.Series.Next[i].Location + '.';
listItem.innerHTML += ' Cost: <strong_prod>£' + json.Series.Next[i].Price + '</strong_prod>';
myList.appendChild(listItem);
}
<div id="my-list">
</div>

How to find number of items which contains specific string using js filter method

I would like to find number of items which has specific text using js filter method.
var num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
num is an object;
Now, i want to find number of categories which has text 'cat'. So i want the result 2. How to get that using filter method.
here's how you can do it
var num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
console.log( num.filter(i => i.category.indexOf("cat") === 0).length )
num is an object;
True, but specifically it's an array object.
You could use filter for this, but reduce would be the more appropriate option if you don't want the array of matching results:
var result = num.reduce(function(sum, entry) => sum + (entry.category.includes("cat") ? 1 : 0), 0);
Live Example:
var num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
var result = num.reduce(function(sum, entry) {
return sum + (entry.category.includes("cat") ? 1 : 0);
}, 0);
console.log(result);
Or with ES2015+:
const num =
[
{
"name": "name1 ",
"category": "test"
},
{
"name": " name2",
"category": "test2"
},
{
"name": "name3",
"category": "cat3"
},
{
"name": "name 4",
"category": "cat 4"
}
];
const result = num.reduce((sum, entry) => sum + (entry.category.includes("cat") ? 1 : 0), 0);
console.log(result);
Or of course, a simple for loop.
This is fairly simple. In ES6 the solution would be this:
const countOfCats = num.filter(entry => entry.category.match('cat')).length;
Another way could be:
const countOfCats = num.filter(entry => entry.contains("cat")).length;

Nested JSON to Numbered HTML Table using Javascript

I'm trying to generate HTML table from JSON
The JSON provided is deeply nested. With the help of this thread How do I loop through deeply nested properties of a JavaScript object?, I am able to get the values of the JSON but I am confused on how to generate the HTML table
var districts = {
"district": [{
"ration": 4,
"states": [{
"name": "Louisiana",
"population": 42383,
"cities": [{
"name": "Cavalero"
}]
}]
}, {
"ration": 1,
"states": [{
"name": "Colorado",
"population": 980,
"cities": []
}, {
"name": "Arkansas",
"population": 58998,
"cities": []
}, {
"name": "Illinois",
"population": 59333,
"cities": [{
"name": "Kenwood"
}]
}]
}, {
"ration": 2,
"states": [{
"name": "Washington",
"population": 83984,
"cities": [{
"name": "Conestoga"
}, {
"name": "Whitehaven"
}, {
"name": "Dellview"
}]
}, {
"name": "West Virginia",
"population": 38034,
"cities": []
}]
}]
};
var i, district, j, states, k, cities;
for (i = 0; i < districts.district.length; i++) {
district = districts.district[i];
print(i + 1, ". District", i + 1, "consists of following states", "--- ration", district.ration);
for (j = 0; j < district.states.length; j++) {
states = district.states[j];
var said = (states.cities.length > 0) ? ("consists of following cities") : ("");
print(i + 1, ".", j + 1, states.name, said, "--- population", states.population);
for (k = 0; k < states.cities.length; k++) {
cities = states.cities[k];
print(" ", i + 1, ".", j + 1, ".", k + 1, cities.name);
}
}
}
Run this on Ideone
Any pointers/help/suggestions appreciated
You will need to generate a table, like this:
var districts = {
"district": [{
"ration": 4,
"states": [{
"name": "Louisiana",
"population": 42383,
"cities": [{
"name": "Cavalero"
}]
}]
}, {
"ration": 1,
"states": [{
"name": "Colorado",
"population": 980,
"cities": []
}, {
"name": "Arkansas",
"population": 58998,
"cities": []
}, {
"name": "Illinois",
"population": 59333,
"cities": [{
"name": "Kenwood"
}]
}]
}, {
"ration": 2,
"states": [{
"name": "Washington",
"population": 83984,
"cities": [{
"name": "Conestoga"
}, {
"name": "Whitehaven"
}, {
"name": "Dellview"
}]
}, {
"name": "West Virginia",
"population": 38034,
"cities": []
}]
}]
};
//Start of the table, including header
var table = '<table><thead><tr><th>Num</th><th>District</th><th>Population</th><th>Ration</th></tr></thead><tbody>';
//Num
for (var i = 0; i < districts.district.length; i++) {
//District
var district = districts.district[i];
//First row
table += '<tr><td>' + (i + 1) + '</td><td>District ' + district.ration + ' consists of the following states:</td><td></td><td>' + district.ration + '</td></tr>';
//States
var states = district.states;
for (var j = 0; j < states.length; j++) {
table += '<tr><td></td><td>' + (i + 1) + '.' + (j + 1) + ' ' + states[j] + ((states[j].cities && states[j].cities.length) ? ' consists of following cities:' : '') + '</td><td>' + states[j].population + '</td><td></td></tr>';
//Cities
if (states[j].cities) {
for (var k = 0; k < states[j].cities; k++) {
table += '<tr><td></td><td>' + (i + 1) + '.' + (j + 1) + '.' + (k + 1) + ' ' + states[j].cities[k].name + '</td><td></td><td></td></tr>';
}
}
}
}
//End of the table
table += '</tbody></table>';
and then add table somewhere into your html.
if you want to generate the desired output as on that link, you can use
<ol>
<li></li>
<li>
<ol><li></li></ol>
<li>
</ol>
instead of table. generate it using javascript. you can use below code to generate your ordered list which should be inserted on the main ordered list tag.
var district = districts.district;
function generateCities(cities){
cities.map((city) => {
return (
"<li>"+ city.name + "</li>"
)
})
}
function generateStates(states, generateCities){
states.map((stat) => {
return (
"<li>"+stat.name + " consists of following cities --- population " + stat.population + "</li>"
+"<ol>" + generateCities(stat.cities) + "</ol>"
)
});
}
function generateMyHtml(district, generateStates){
district.map((dist, index) => {
return (
"<li> District "+ index + "consists of following states --- ration " + dist.ration + "</li>"
+"<ol>" + generateStates(dist.states) + "</ol>"
)
});
};
hope this is helpful

Create JSON object with same keys for API call

I'm trying to create a JSON object for an API call which has the following format:
....
"Key": "Value",
"Package": {
"Dimensions": {
"UnitOfMeasurement": {
"Code": "IN",
"Description": "inches"
},
"Length": "20",
"Width": "25",
"Height": "30"
},
"PackageWeight": {
"UnitOfMeasurement": {
"Code": "Lbs",
"Description": "pounds"
},
"Weight": "80"
}
},
"Package": {
"Dimensions": {
"UnitOfMeasurement": {
"Code": "IN",
"Description": "inches"
},
"Length": "15",
"Width": "24",
"Height": "27"
},
"PackageWeight": {
"UnitOfMeasurement": {
"Code": "Lbs",
"Description": "pounds"
},
"Weight": "50"
}
},
"Key": "Value",
....
I should add as many "Package" objects as needed. However, I've tried doing this in many different ways but every time that I parse the variable to be used the first objects get overwritten and I end up with only the last object.
This is what I'm trying at the moment, still with no luck:
var lineItems = '{';
for (var i=0;i<inputObject.packages.length;i++) {
lineItems += '"Package": {"PackagingType": {"Code": "02","Description": "Rate"},"Dimensions": {"UnitOfMeasurement": {"Code": "IN","Description": "inches"},"Length": ' + inputObject.packages[i][0].toString() + ',"Width": ' + inputObject.packages[i][1].toString() + ',"Height": ' + inputObject.packages[i][2].toString() + '},"PackageWeight": {"UnitOfMeasurement": {"Code": "Lbs","Description": "pounds"},"Weight": ' + inputObject.packages[i][3].toString() + '}}';
if (i !== inputObject.packages.length-1) {
lineItems += ',';
}
}
lineItems += '}';
lineItems = JSON.parse(lineItems);
How about numbering your packages, ie:
for (var i=0;i<inputObject.packages.length;i++) {
lineItems+='"Package" + i : { ... }'
}
edit: to get required result (as an array - because it's not JSON), here's an example:
var a=[];
var b={"package": {"c":100,"d":200,"e":300}}
var c={"package": {"c":800,"d":700,"e":600}}
a.push(b);
a.push(c);
console.log(a);

drill down through json data

Im experimenting with the espn public API and am trying to use their json to access NFL player information.
the json im accessing succesfully looks like:
{
"sports": [
{
"name": "football",
"id": 20,
"leagues": [
{
"name": "National Football League",
"abbreviation": "nfl",
"id": 28,
"groupId": 9,
"shortName": "NFL",
"athletes": [
{
"id": 14466,
"firstName": "Isa",
"lastName": "Abdul-Quddus",
"fullName": "Isa Abdul-Quddus",
"displayName": "Isa Abdul-Quddus",
"shortName": "I. Abdul-Quddus",
"links": {
"api": {
"athletes": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/14466"
},
"news": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/14466/news"
},
"notes": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/14466/news/notes"
}
},
"web": {
"athletes": {
"href": "http://espn.go.com/nfl/player/_/id/14466/isa-abdul-quddus?ex_cid=espnapi_public"
}
},
"mobile": {
"athletes": {
"href": "http://m.espn.go.com/nfl/playercard?playerId=14466&ex_cid=espnapi_public"
}
}
}
},
{
"id": 8645,
"firstName": "Hamza",
"lastName": "Abdullah",
"fullName": "Hamza Abdullah",
"displayName": "Hamza Abdullah",
"shortName": "H. Abdullah",
"links": {
"api": {
"athletes": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/8645"
},
"news": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/8645/news"
},
"notes": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/8645/news/notes"
}
},
"web": {
"athletes": {
"href": "http://espn.go.com/nfl/player/_/id/8645/hamza-abdullah?ex_cid=espnapi_public"
}
},
"mobile": {
"athletes": {
"href": "http://m.espn.go.com/nfl/playercard?playerId=8645&ex_cid=espnapi_public"
}
}
}
},
{
"id": 11910,
"firstName": "Husain",
"lastName": "Abdullah",
"fullName": "Husain Abdullah",
"displayName": "Husain Abdullah",
"shortName": "H. Abdullah",
"links": {
"api": {
"athletes": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/11910"
},
"news": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/11910/news"
},
"notes": {
"href": "http://api.espn.com/v1/sports/football/nfl/athletes/11910/news/notes"
}
} ........
]
}
]
}
],
"resultsOffset": 0,
"resultsLimit": 50,
"resultsCount": 3301,
"timestamp": "2013-01-06T19:30:17Z",
"status": "success"
}
and heres the html / javascript Im using:
$(document).ready(function(){
$.getJSON("http://api.espn.com/v1/sports/football/nfl/athletes?apikey=MY-API-KEY-HERE&_accept=application/json",
function(data){
$.each(data["sports"], function(i,item){
$("#infoDiv").append( [i] + " - " + item.name + "<br>" );
});
});
});
i can get this to display 0 - football but cant use something like
$.each(data["sports"]["leagues"]["athletes"], function(i,item){
$("#infoDiv").append( [i] + " - " + item.firstName + "<br>" );
to access the individual athlete data such as item.firstName , etc.
i keep getting the following error:
TypeError: data.sports.leagues is undefined
what am I missing? I'm using this same code structure successfully with a couple of other API's that provide json. the ESPN json is a little more complex in comparison though.
thanks for any light you can shed on this for me.
sports, leagues and athletes are arrays, for example: sports[0] is an object (the one with name='football')
You should iterate each like this (not tested):
$.each(data.sports, function(i,sport) {
$.each(sport.leagues, function(i,league) {
$.each(league.athletes, function(i,athlete) {
$("#infoDiv").append( [i] + " - " + athlete.firstName + "<br>" );
});
});
});
sports, leagues and athletes are arrays which you need to iterate.
for (var i=0; i<data.sports.length; i++) {
var sport = data.sports[i];
$("#infoDiv").append( [i] + " - " + sport.name + "<br>" );
for (var j=0; j<sport.leagues.length; j++) {
var league = sport.leagues[j];
$("#infoDiv").append( [i,j] + " - " + league.name + "<br>" );
for (var k=0; k<league.athletes.length; k++) {
var athlete = league.athletes[k];
$("#infoDiv").append( [i,j,k] + " - " + athlete.fullName + "<br>" );
}
}
}

Categories