I would like to replicate this example data set into nested JSON using JavaScript or Angularjs or any javascript library.
Data:
PrimaryId,FirstName,LastName,City,CarName,DogName
100,John,Smith,NewYork,Toyota,Spike
100,John,Smith,NewYork,BMW,Spike
100,John,Smith,NewYork,Toyota,Rusty
100,John,Smith,NewYork,BMW,Rusty
101,Ben,Swan,Sydney,Volkswagen,Buddy
101,Ben,Swan,Sydney,Ford,Buddy
101,Ben,Swan,Sydney,Audi,Buddy
101,Ben,Swan,Sydney,Volkswagen,Max
101,Ben,Swan,Sydney,Ford,Max
101,Ben,Swan,Sydney,Audi,Max
102,Julia,Brown,London,Mini,Lucy
Javascript:
var file = reader.result;
var singleRow = readerFile.split(/\r\n|\n/);
var header = singleRow[0].split(',');
var result =[];
for ( var i=1; i < file.length; i++ ){
var elementData = singleRow[i].split(',');
elementData = elementData.filter(function(n){ return n != "" });
var Obj = {};
for ( var j=0; j < header.length; j++ ){
Obj[header[j]] = elementData[j];
/*
- How can i build child object and append back to Obj before j loop
- How can i build multiple child for same parent
*/
}
result.push(Obj);
}
console.log(" Print the JSON Object : " + JSON.stringify(result));
Desired Output:
{
"data": [
{
"City": "NewYork",
"FirstName": "John",
"PrimaryId": 100,
"LastName": "Smith",
"CarName": [
"Toyota",
"BMW"
],
"DogName": [
"Spike",
"Rusty"
]
},
{
"City": "Sydney",
"FirstName": "Ben",
"PrimaryId": 101,
"LastName": "Swan",
"CarName": [
"Volkswagen",
"Ford",
"Audi"
],
"DogName": [
"Buddy",
"Max"
]
},
{
"City": "London",
"FirstName": "Julia",
"PrimaryId": 102,
"LastName": "Brown",
"CarName": [
"Mini"
],
"DogName": [
"Lucy"
]
}
]
}
If Firstname, Lastname and City has same values then CarName and DogName values should be child object under the same parent
I reformatted your initial code a little bit, but it doesn't change the initial logic. One key observation is that even if the FirstName, LastName and City are the same, that may not be a unique person, hence you should use the PrimaryId instead, to determine uniqueness.
Look at the post-processing section for the new code:
const data = `PrimaryId,FirstName,LastName,City,CarName,DogName
100,John,Smith,NewYork,Toyota,Spike
100,John,Smith,NewYork,BMW,Spike
100,John,Smith,NewYork,Toyota,Rusty
100,John,Smith,NewYork,BMW,Rusty
101,Ben,Swan,Sydney,Volkswagen,Buddy
101,Ben,Swan,Sydney,Ford,Buddy
101,Ben,Swan,Sydney,Audi,Buddy
101,Ben,Swan,Sydney,Volkswagen,Max
101,Ben,Swan,Sydney,Ford,Max
101,Ben,Swan,Sydney,Audi,Max
102,Julia,Brown,London,Mini,Lucy`;
var singleRow = data.split(/\r\n|\n/);
var header = singleRow[0].split(',');
var result =[];
for (var i = 1; i < singleRow.length; i++) {
var elementData = singleRow[i].split(',');
elementData = elementData.filter(function(n) { return n != '' });
var Obj = {};
for ( var j=0; j < header.length; j++ ){
Obj[header[j]] = elementData[j];
}
result.push(Obj);
}
console.log(JSON.stringify(result, null, 2));
// Post-processing code starts here
const people = {};
// Create a map of unique people first
result.forEach(function (object) {
if (!people[object.PrimaryId]) {
people[object.PrimaryId] = {
City: object.City,
FirstName: object.FirstName,
PrimaryId: object.PrimaryId,
LastName: object.LastName,
CarName: [],
DogName: [],
};
}
// As you iterate through your results, if this person already exists
// add to their array of car and dogs.
people[object.PrimaryId].CarName.push(object.CarName);
people[object.PrimaryId].DogName.push(object.DogName);
});
// Convert back into an array
const peopleList = [];
Object.keys(people).forEach(function (primaryId) {
peopleList.push(people[primaryId]);
})
console.log(peopleList);
First of all, since you already know the property names, there's no point in parsing the first row.
I would do something like this:
let results = {};
for (let i = 1; i < file.length; i++) {
let entry = getEntry(results, file[i][0]);
entry.DogName.push(file[i][DOGNAME_INDEX]);
entry.CarName.push(file[i][CARNAME_INDEX]);
entry.LastName = file[i][LASTNAME_INDEX];
...
}
// and now to convert this into an array
let array = Object.keys(results).map(key => results[key]);
// retrieves or creates an entry for a given primary key
function getEntry(results, id) {
return results[id] || (results[id] = {});
}
You could also get fancier and dynamically determine what the column indexes are, but the way I have it just keeps things simple.
Made a fiddle for you, it gives the desired output with some things in a different order than you presented.
You can save the indexes of the headers:
var Index = {};
for(var k = 0; k < header.length; k++)
{
Index[header[k]] = k;
}
And keep a list of cities:
var cities = [];
....
cities.push(data[Index["City"]]);
To use for later so that you don't keep making more objects if the city already exists:
obj = result.data[cities.indexOf(data[Index["City"]])];
The JSFiddle: https://jsfiddle.net/3u28aon3/1/
Related
I'm having trouble wrapping my mind around javascript hashmaps and JSON arrays. I'm trying to count duplicate import countries from a JSON array. For instance the data is:
[
{
"id": 1,
"import_country": "Russia",
"model": "Express 2500",
"make": "Chevrolet",
"sold_by": "Sibylla Kneale",
"sale_price": 14702
},
{
"id": 2,
"import_country": "Philippines",
"model": "G-Class",
"make": "Mercedes-Benz",
"sold_by": "Gabie Gradwell",
"sale_price": 19142
},
{
"id": 3,
"import_country": "Russia",
"model": "M",
"make": "Infiniti",
"sold_by": "Burl Pitkeathley",
"sale_price": 18395
}
]
This is what I have for code so far:
var country = [];
var temp = [];
const model = [];
const count = 0;
const response = await fetch('some api url where data is retrieved')
.then(response => response.json())
.then(data => {
var key = {};
for(i = 0; i< data.length; i++){
if(temp.indexOf(data[i].import_country) == -1){
temp.push(data[i][import_country]);
var _data = {};
}
}
});
My end goal is to have the total country count displayed on a graph.
A good way to do this would be to use a hashmap instead of arrays like you said.
If we update your code to be this:
var hashmap = {};
const response = await fetch('some api url where data is retrieved')
.then(response => response.json())
.then(data => {
var key = {};
for(i = 0; i< data.length; i++){
let country = data[i]['import_country'];
if (hashmap[country] == void(0)) { // if it doesn't exist in the hashmap
hashmap[country] = []; // create it in the map
}
hashmap[country].push(data[i]); // add it to the country array in the temp
}
})
If the data you are receiving above is correct, the output would look something like this:
{
"Russia": [
{"id":1,"import_country":"Russia","model":"Express 2500","make":"Chevrolet","sold_by":"Sibylla Kneale","sale_price":14702},
{"id":3,"import_country":"Russia","model":"M","make":"Infiniti","sold_by":"Burl Pitkeathley","sale_price":18395}
],
"Phillipines": [
{"id":2,"import_country":"Philippines","model":"G-Class","make":"Mercedes-Benz","sold_by":"Gabie Gradwell","sale_price":19142}
]
}
Now that we have the data formatted how we would like, we can loop through it to get the total country count:
... // code from above
for (var country in map) {
console.log(country + ": " + country.length + " cars");
}
That code would output:
Russia: 2 cars
Phillipines: 1 cars
Try below code -
var jsonArray = [{"id":1,"import_country":"Russia","model":"Express 2500","make":"Chevrolet","sold_by":"Sibylla Kneale","sale_price":14702},{"id":2,"import_country":"Philippines","model":"G-Class","make":"Mercedes-Benz","sold_by":"Gabie Gradwell","sale_price":19142},{"id":3,"import_country":"Russia","model":"M","make":"Infiniti","sold_by":"Burl Pitkeathley","sale_price":18395}];
var map = new Map();
for(var i=0;i<jsonArray.length;i++){
if(!map.get(jsonArray[i].import_country)){
map.set(jsonArray[i].import_country,1);
}else{
map.set(jsonArray[i].import_country, map.get(jsonArray[i].import_country) + 1);
}
}
Pseudo Code:-
Getting a JSON array.
Creating an empty map.
for i=0 to JSON Array length.
a. if the map doesn't contain the country, then set the country with count 1.
b. else set already existing key in the map by increasing with count 1.
End.
file structure
this._formService.arraySteps[j].profile[i].nom = newValue;
where i and j are indexes
How can I make this works using variable instead of text.
I've tried the following where
tmpKeyName = "profile"
keyObject = "nom"
this._formService.arraySteps[j][tmpKeyName][i][keyObject];
Thanks
Assuming that your array/object structure is correct, your code would work:
// let's assume that this._formService.arraySteps was the following array of objects:
var arraySteps = [
{
profile: [
{nom: "something"}
]
},
{
profile: [
{nom: "something else"}
]
},
{
profile:[
{nom: "something totally different"}
]
}
];
var tmpKeyName = "profile";
var keyObject = "nom";
// Looping through that array:
for(var j = 0; j < arraySteps.length; ++j){
// Looping through the objects in the array:
for(var i = 0; i < arraySteps[j][tmpKeyName].length; ++i){
console.log(arraySteps[j][tmpKeyName][i][keyObject]);
}
}
I'm getting an XML and parsing it, saving it to array, the problems is that I get objects in this order:
temp1.ID = 15
temp1.name = "Dan"
temp1.phone = "32332"
temp2.ID = 12
temp2.name = "Test"
temp2.phone = 53463
temp3.ID = 2
temp3.name = "Tom"
temp3.phone = 12443
.
.
.
.
Object - its an objects that I get inside a loop while parsing XML
What I try is to save them in the same order I started to read them : Array: [temp1,temp2,temp3]
But The result of the next function is : Array: [temp3,temp2,temp1]
the function:
this.mytempect = [];
for (var i = 0; i < xml.length; i++) {
var temp = {};
temp.ID = parseXmlByTag(xml[i], "ID");
temp.name = parseXmlByTag(xml[i], "name");
temp.phone = parseXmlByTag(xml[i], "phone");
if (this.mytempect [temp .ID] == null) {
this.mytempect [temp .ID] = [];
}
this.mytempect [temp .ID].push(obj);
}
Before I save each object I check if I need to create for him a new Key or to add to existing one, in the end I get something like this:
I need to save the order in which I'm getting them so I'll save them in the order I entered them
If I understand your question here's what I think you should be doing. You seem to be confusing objects and arrays: mytempect needs to be an object if you want to store arrays against a key set by the ID.
Following your example, objects with the same key are assigned to the same array (identified by that key in the object) in the order in which they are read.
// create an object, not an array
this.mytempect = {};
for (var i = 0; i < arr.length; i++) {
var temp = {};
temp.ID = arr[i].ID;
temp.name = arr[i].name;
temp.phone = arr[i].phone;
// Don't check for null here because `this.mytempect[temp.ID]` might not exist
if (!this.mytempect[temp.ID]) {
this.mytempect[temp.ID] = [];
}
this.mytempect[temp.ID].push(temp);
}
DEMO
The demo produces an object with one object in an array under key 15, two under 12 and one under 2:
{
"2": [
{
"ID": 2,
"name": "Tom",
"phone": 12443
}
],
"12": [
{
"ID": 12,
"name": "Test",
"phone": 53463
},
{
"ID": 12,
"name": "Test",
"phone": 53462
}
],
"15": [
{
"ID": 15,
"name": "Dan",
"phone": "32332"
}
]
}
Note: you can't order the object in any way.
Perhaps you're looking for something like this
var mytempect = [],
dict = {},
i,
tmp;
for (i = 0; i < xml.length; ++i) {
tmp = {
ID: parseXmlByTag(xml[i], "ID"),
name: parseXmlByTag(xml[i], "name"),
phone: parseXmlByTag(xml[i], "phone")
};
if (!(tmp.ID in dict)) {
mytempect.push(dict[tmp.ID] = []);
}
dict[tmp.ID].push(tmp); // use fact Objects ByRef to add item
}
dict = null; // cleanup
The Array mytempect will now have indices 0, 1, 2, etc containing Arrays of all Objects which have the same ID. With your sample data you will get
mytempect[0][0].ID === 15;
mytempect[1][0].ID === 12;
mytempect[2][0].ID === 2;
I want to add javascript array values into JSON values object. The other element is also replaced my element like recipients, subject, message. I got Json like:
Below is my code.
var BODY = {
"recipients": {
"values": [
]
},
"subject": title,
"body": message
}
var values = [];
for (var ln = 0; ln < names.length; ln++) {
var item1 = {
"person": {
"_path": "/people/"+names[ln],
},
};
values.push(item1);
}
BODY = JSON.stringify({values: values});
alert(BODY);
I think you want to make objects from array and combine it with an old object (BODY.recipients.values), if it's then you may do it using $.extent (because you are using jQuery/tagged) method after prepare the object from array
var BODY = {
"recipients": {
"values": []
},
"subject": 'TitleOfSubject',
"body": 'This is the message body.'
}
var values = [],
names = ['sheikh', 'muhammed', 'Answer', 'Uddin', 'Heera']; // for testing
for (var ln = 0; ln < names.length; ln++) {
var item1 = {
"person": { "_path": "/people/"+names[ln] }
};
values.push(item1);
}
// Now merge with BODY
$.extend(BODY.recipients.values, values);
DEMO.
If you want to stick with the way you're populating the values array,
you can then assign this array like so:
BODY.values = values;
after the loop.
It should look like this:
var BODY = {
"recipients": {
"values": [
]
},
"subject": title,
"body": message
}
var values = [];
for (var ln = 0; ln < names.length; ln++) {
var item1 = {
"person": {
"_path": "/people/"+names[ln],
},
};
values.push(item1);
}
BODY.values = values;
alert(BODY);
JSON.stringify() will be useful once you pass it as parameter for an AJAX call.
Remember: the values array in your BODY object is different from the var values = [].
You must assign that outer values[] to BODY.values. This is one of the good things about OOP.
You can directly access BODY.values:
for (var ln = 0; ln < names.length; ln++) {
var item1 = {
"person": {
"_path": "/people/"+names[ln],
},
};
BODY.values.push(item1);
}
var arr = [ 'a', 'b', 'c'];
arr.push('d'); // insert as last item
var d=getEntity( {"Division":
{
"oddTerms":
[
{
"entity": "Sunshine",
"Sunshine": [
{
"count": 2,
"entity": "Dodge"
},
{
"count": 1,
"entity": "Dodge Avenger"
},
]
}
]
}});
I want to traverse through the json string and the the entity names Dodge and Dodge Avenger. Ive used the following method
for (var k in h.Division.oddTerms)
{
s=h.Division.oddTerms[k].entity;
h.Division.oddTerms[k].+s+.entity;
}
But I do think this its not the correct methd to concatenate as it is not wrking.. anyone knows the correct format?
oddTerms is an Array, not an Object. For arrays in JavaScript you need to use a for loop with a counter instead of iterating through the elements:
var concatedString = '';
for (var k=0; k<h.Division.oddTerms.length;k++)
{
// Get the name of the entity we want to collect the entity terms of
var entityName =h.Division.oddTerms[k].entity;
// iterate through all the instances of each entity
for(var j=0; j<h.Division.oddTerms[k][entityName].length;j++){
concatedString += h.Division.oddTerms[k][entityName][j].entity;
}
}
var entityName = "",
arrTerms = [],
outputTemplate = '{"%entityName":[%terms]}',
h = {
"Division":
{
"oddTerms":
[
{
"entity": "Sunshine",
"Sunshine": [
{
"count": 2,
"entity": "Dodge"
},
{
"count": 1,
"entity": "Dodge Avenger"
},
]
}
]
}
};
for (var i = 0; i < h.Division.oddTerms.length; i++)
{
entityName=h.Division.oddTerms[i].entity; // "Sunshine"
terms = h.Division.oddTerms[i][entityName];
for (var j = 0; j < terms.length; j++) {
arrTerms.push('"' + terms[j].entity + '"');
}
}
// This will give you '{"Sunshine":["Dodge","Dodge Avenger"]}':
console.log(outputTemplate.replace('%entityName', entityName).replace('%terms', arrTerms.join(",")));
Edit:
Just some more on this.
JSON can be a bit confusing to work with if you're not used to working with JS and object and array "literals". In JS you can define objects and arrays in a number of ways, but the easiest (and the most preferred, by many developers) is with these literals.
Here's an example of an object:
var myObj = {
"some prop":"some value",
"anotherProp":"another value"
}
You can look up the members of myObj in several ways:
myObj.anotherProp // "another value"
myObj["some prop"] // you have to use this form if the property name has a space in it
For looping through the contents of an array, use the second form. For example, this won't work:
for (var strPropName in myObj) {
console.log(myObj.strPropName); // This won't work!
}
Instead, you should loop through the properties like this:
for (var strPropName in myObj) {
if (myObj.hasOwnProperty(strPropName)) {
console.log(myObj[strPropName]);
}
}
The if block is optional, but you'll avoid potential problems if you always include this in your code. It's also required by some validators.
Now, here's an example of an array:
var myArray = ["some value", "anotherValue"];
You access these with a numeric index:
myArray[0] // "some value"
myArray[1] // "anotherValue"
myArray[2] // undefined
And you can loop through them:
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
You can nest objects inside arrays:
myArray = [{},{},{}];
And you can nest arrays inside objects:
myObject = {"arr1":[], "arr2":[], "arr3":[]}