Split JSON value to obtain new JSON with news properties - javascript

This is my first post today because I'm exhausted.
I try since few days to make something that looks simple but not for me...
I've this JSON :
[
{
"GpName":"AAAAAA",
"Contacts":"US;Toto;\nESI;James;james#mail.com "
},
{
"GpName":"BBBBBB",
"Contacts":"ESI;Sebastien;sebastien#mail.com\nUS;Ahmid;\nESI;Stephane ;Stephane#mail.com"
},
{
"GpName":"CCCCCC",
"Contacts":"ESI;Marc;Marc#mail.com\nUS;Olivier;olivier#mail.com\nUS;Jean;jean#mail.com"
}
]
I try to use the split array function, I don't have the result expected.
How could I obtain :
[
{
"GpName":"AAAAAA",
"Contacts":["Zone":"US",
"User":"Toto"
"Mail": " "],
["Zone":"ESI",
"User":"James",
"Mail":"james#gmail.com "]
},
{
"GpName":"BBBBBB",
"Contacts":["Zone":"ESI",
"User":"Sebastien"
"Mail": "sebastien#mail.com"],
["Zone":"US",
"User":"Ahmid ",
"Mail":" "]
["Zone":"ESI",
"User":"Stephane",
"Mail":"Stephane#mail.com"]
},
{
"GpName":"CCCCCC",
"Contacts":["Zone":"ESI",
"User":"Marc"
"Mail": "Marc#mail.com"],
["Zone":"US",
"User":"Olivier",
"Mail":" "]
["Zone":"US",
"User":"Jean",
"Mail":"Jean#mail.com"]
}
]
As you can see, sometimes I've email, sometime not.
Any help would be very grateful

use Array.split Split a string into substrings and Array.map to generate an array.
let input = [{ "GpName": "AAAAAA", "Contacts": "US;Toto;\nESI;James;james#mail.com " }, { "GpName": "BBBBBB", "Contacts": "ESI;Sebastien;sebastien#mail.com\nUS;Ahmid;\nESI;Stephane ;Stephane#mail.com" }, { "GpName": "CCCCCC", "Contacts": "ESI; Marc; Marc#mail.com\nUS; Olivier; olivier#mail.com\nUS; Jean; jean#mail.com" }]
let result = input.map(({ GpName, Contacts }) => ({
GpName,
Contacts: Contacts.split("\n").map(line => {
let [Zone, User, Mail] = line.split(";");
return { Zone, User, Mail }
})
}));
console.log(result)

What I tried on my side
var EsiEmailList = [];
var EsiEmailListJSON = [];
var myJSON = JSON.parse(BgManagerInfoList);
for (key in myJSON) {
gpInfo = myJSON[key];
var gpName= gpInfo.GpName;
var gpContact = gpInfo.Contacts;
EsiEmailListJSON.push(gpContact);
}
EsiEmailList=JSON.stringify(EsiEmailListJSON);
EsiEmailListSplit = EsiEmailListJSON/split("\n");
for (data in EsiEmailListSplit){
contactInfo = EsiEmailListJSON[data];
System.log ("contactInfo: " + contactInfo);
}
The result is something like this :
**ContactInfo**: US;Toto;
ESI;James;james#mail.com
**ContactInfo**: ESI;Sebastien;sebastien#mail.com
US;Ahmid;
ESI;Stephane;Stephane#mail.com
**ContactInfo**:ESI;Marc;Marc#mail.com
US;Olivier;olivier#mail.com
US;Jean;jean#mail.com

same issue :
Error in (Workflow:TEst / map function (item1)#37) TypeError: Cannot find function map in object
I tested the polyfill but it's not working
Here the code
if (!Array.prototype.map) {
Array.prototype.map = function(callback/*, thisArg*/) {
var T, A, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
A[k] = mappedValue;
}
k++;
}
return A;
};
}
var input = [{ "GpName": "AAAAAA", "Contacts":
"US;Toto;\nESI;James;james#mail.com " }, { "GpName": "BBBBBB", "Contacts":
"ESI;Sebastien;sebastien#mail.com\nUS;Ahmid;\nESI;Stephane ;Stephane#mail.com"
}, { "GpName": "CCCCCC", "Contacts": "ESI; Marc; Marc#mail.com\nUS; Olivier;
olivier#mail.com\nUS; Jean; jean#mail.com" }];
var result = input.map(function (_a) {
var GpName = _a.GpName, Contacts = _a.Contacts;
return ({
GpName: GpName,
Contacts: Contacts.split("\n").map(function (line) {
var _a = line.split(";"), Zone = _a[0], User = _a[1], Mail = _a[2];
return { Zone: Zone, User: User, Mail: Mail };
})
});
});
Can I Maybe use the for each instead of map, something like this :
var inputJSON = JSON.parse(BgManagerInfoList);
for each(a in inputJSON ){
var GpName = a.GpName;
var Contacts = a.Contacts;
//System.log ("GpName: " + GpName);
//System.log ("Contacts: " + Contacts);
for each(b in Contacts){
b = line.split(";");
var Zone = b[0];
var User = b[1];
var Mail = b[2];
System.log ("Zone:" + Zone + ", User: " + User + ", Mail: " + Mail );
}
}
I've a value for GpName and Contacts but the for each is not working for Contacts

I found the solution of my problem :
var input = JSON.parse(BgManagerInfoList);
for each(a in input){
var GpName = a.GpName ;
var Contacts = a.Contacts;
//System.log ("GpName: " + GpName);
contactSplit = Contacts.split('\n');
System.log ("Contacts: " + Contacts);
for each (a in contactSplit){
var ContactOnly = a.split(";");
//System.log ("ContactsSplit: " + ContactsSplit);
var Zone = ContactOnly[0];
var User = ContactOnly[1];
var Mail = ContactOnly[2];
System.log ("Zone:" + Zone + ", User: " + User + ", Mail: " + Mail );
}
}
I made a first split of each lines, and for each line I made another split on the ";".
I got the expected result. Tks a lot for your suggestion, they helped me to understand of map is working and adapt my code to get the result.
I've to push the result in a table and work with.

Related

How to readrecords from Json Array

I try to use Javascript Ext libraries and call a rest service which returns a json response. Its an array with one element and it doesnt work when i use DataReader(Ext.data.DataReader) "readRecords" operation to process the json data and it returns null reference on the call back function.
It would be good if you provide some help or suggestions to fix the issue.
I tried to pass the array as the argument in the reader and it doesnt help.
Ext.namespace("cityDetails");
var a = "http://" + "Url address to get cityDetails";
var e = new Ext.data.ScriptTagProxy({
callbackParam: "callback",
url: a
});
var f = {
fields: [{
name: "Id"
}, {
name: "city"
}, {
name: "postcode"
}]
};
var d = new cityDetails.reader(f, {});
//call back function
var h = function(k, j, m) {
try {
// k returns null reference
if (k != null) {
alert("PostCode insider else::" + k.jsonObject.postcode)
}
}
} catch (l) {
alert(l)
}
};
var i = this;
e.load({
1: 1
}, d, h, i)
//readRecords from Data - Json Response an array of one objekt
Ext.extend(cityDetails.reader, Ext.data.DataReader, {
readRecords: function(b) {
this.jsonData = b;
alert("Meta ::" + this.meta);
//alert("Meta Root::"+this.meta.root);
var a = false;
return {
success: a,
jsonObject: this.getRoot(b),
totalRecords: 1
}
},
getRoot: function(d) {
if (this.meta && this.meta.root) {
var c = d;
var a = this.meta.root.split(".");
for (var b = 0; b < a.length; b++) {
c = c[a[b]]
}
return c
} else {
alert("Value Of d in reader::" + d);
if (d != null) {
alert("Objects Of d in reader::" + d.jsonObject.postcode);
}
return d
}
}
})
//Initial call.
cityDetails.reader = function(a, b) {
a = a || {};
cityDetails.reader.superclass.constructor.call(this, a, b || a.fields)
};
Sample response from rest service shown below.
[{
"Id": "121A",
"postcode": "1000",
"city": "ABBA"
}]
The call back function k should return the value of Json response. However it returns null.

how to parse a .RC file using Javascript

I am trying to parse the data from a .RC (resource definition file) to JSON using js with simple fs.readFile function, however I am getting SyntaxError: Invalid or unexpected token. At the moment I've found no other solution to parse this type of file, pls provide me with inputs to do so. Below is .RC example.
#include "shapes.h"
ShapesCursor CURSOR SHAPES.CUR
ShapesIcon ICON SHAPES.ICO
ShapesMenu MENU
{
POPUP "&Shape"
{
MENUITEM "&Clear", ID_CLEAR
MENUITEM "&Rectangle", ID_RECT
}
}
I found a package in node called, 'Jison' which is an API for creating parsers in JavaScript similar to 'PegJS', however I couldn't figure out the grammer that needs to be written for my file type also if it would support the file type. The parsed structure could look similar to,
{
"directive": [
"include",
"shapes.h"
],
"data": [
{
"name": "ShapesCursor",
"values": [
"CURSOR",
"SHAPES.CUR"
],
"children": []
},
{
"name": "ShapesIcon",
"values": [
"CURSOR",
"SHAPES.ICO"
],
"children": []
},
{
"name": "POPUP",
"values": [
"&Shape"
],
"children": [
{
"name": "MENUITEM",
"values": [
"&Clear",
"ID_CLEAR"
],
"children": []
},
{
"name": "MENUITEM",
"values": [
"&Rectangle",
"ID_RECT"
],
"children": []
}
]
}
]
}
Below grammar can be used for parsing Resource Description files to a JSON.
{
var word_Obj = {};
var word_alnum_Obj = {};
var word_alnumsp_Obj = {};
var dir_Obj = {};
var valStateDec_Obj = {};
var stateName_Obj = {};
var valStateVal_Obj = {};
var word_Count = 0;
var word_alnum_Count = 0;
var word_alnumsp_Count = 0;
var dir_Count = -1;
var valStateDec_Count = 0;
var stateName_Count = -1;
var valStateVal_Count = -1;
var begin_Count = -1;
var end_Count = -1;
var child_Count = -1;
var children_Count = -1;
var flag = 0;
}
Expected = dir:directive * nl * states:state nl* Ending:EOL {if (begin_Count === end_Count) { return { Parsed_RC: { Directive_Obj: dir, States_Obj: states, ENDING: Ending } } } else { return "Incorrect .RC file" } }
directive = "#" d: word space* v:word_alnumsp nl+ { dir_Count++; dir_Obj = { ['Directive_' + dir_Count]: { "Dir": d, "_text": v } }; return dir_Obj;}
state = (valState looping)*
looping = (loopStart loopEnd*)*
loopStart = beg child: valState + { begin_Count++; children_Count++; child_Count++; return {['loopStart_' + begin_Count]: begin_Count, ['child_' + children_Count]: child } }
loopEnd = end {end_Count++; child_Count--; return { ['loopEnd_' + end_Count]: end_Count }; }
valState = stateName(valStateVal) * nl +
//valStateDec = space+ decState_val:word_alnumsp {valStateDec_Count++; valStateDec_Obj = {['ValStateDec_Obj'+valStateDec_Count]:decState_val}; return valStateDec_Obj;}
stateName = space * state_name:word_alnumsp {if (state_name === 'BEGIN') { begin_Count++; children_Count++; child_Count++; return { ['loopStart_' + begin_Count]: begin_Count } } if (state_name === 'END') { end_Count++; child_Count--; return { ['loopEnd_' + end_Count]: end_Count }; } if (child_Count < 0) { flag = 1; } stateName_Count++; stateName_Obj = { ['StateName_Obj' + stateName_Count]: state_name }; return stateName_Obj; }
valStateVal = space + valState_val:(word_alnumsp comma?)* { valStateVal_Count++; valStateVal_Obj = { ['_attributes_Obj' + valStateVal_Count]: valState_val }; return valStateVal_Obj}
word = wo:letter + { return wo.join("") }
word_alnum = al:alnum + { return al.join("") }
word_alnumsp = alsp:alnumsp + { return alsp.join("") }
beg = space * ([{]) space* nl +
end = space * ([}]) space* nl +
comma = space * [,] space* { return ","}
letter = [a - zA - Z]
alnum = [a - zA - Z0 - 9]
alnumsp = [a - zA - Z0 - 9"'&._()\\|+:]
space = " "
nl = '\n' {valStateVal_Count = -1; return "NL"}
EOL = !. {return "EOF"}

Binding an array of objects to their specific form fields for updating/deleting

I need to store form data into an array of objects as a link. Then be able to click the link and fill the form with the objects/data to update or delete.
I'm able to store the form data as objects in an array, but can't figure out how to load it back into the form to update.
var actors = [];
var addActor = function() {
// Assigning Form values to variables
var firstN = $("#fName").val();
var lastN = $("#lName").val();
var gender = $("[name='gender']:checked").val();
var birthdate = $("#birthDate").val();
var action = $("#action").prop('checked');
var comedy = $("#comedy").prop('checked');
var drama = $("#drama").prop('checked');
var sciencefiction = $("#sciencefiction").prop('checked');
var horror =$("#horror").prop('checked');
var suspense = $("#suspense").prop('checked');
// creates newActor variable that contains an object for each input value
var newActor = {fName: firstN, lName: lastN, gender: gender, birthDate: birthdate, action: action, comedy: comedy, drama: drama, suspense: suspense, sciencefiction: sciencefiction, horror: horror}
$("#actorsTable").append("<tr><td><a href='' class='update'>" + newActor.fName + " " + newActor.lName + "</a></td></tr> ");
actors.push(newActor);
console.log(actors);
};
Now my selector function grabs the object but I just don't know how to load it into the form to update and delete. I've been stuck on this for a few days now.
var selectActor = function(e) {
e.preventDefault();
var rowClicked = $(this).parent().parent();
row = rowClicked.index();
alert (actors[row].fName + " " + actors[row].lName + " " + actors[row].gender + " " + actors[row].birthDate + " " + actors[row].action + " " + actors[row].comedy + " " + actors[row].drama + " " + actors[row].suspense + " " + actors[row].sciencefiction + " " + actors[row].horror);
console.log(actors[row]);
};
Here is what I have in action so far. When I check console everything is correct with storing, and selecting, but I can't find anything that shows how to store objects into their respected form fields.
Codepen
Consider using a namespace for your code, then create some generic functions for object manipulations (like an array) as well as some specific to your form.
Note that some libraries like angular, react etc. handle some of this for you, but you asked for the manual part, and it might also be worth some study on one way to do it.
Here is an updated sample to play with: http://codepen.io/MarkSchultheiss/pen/LNqdxK?editors=0010
var myApp = myApp || {};
myApp.arrayObj = {
indexOf: function(myArray, searchTerm, property) {
for (var i = 0; i < myArray.length; i++) {
if (myArray[i][property] === searchTerm) return i;
}
return -1;
},
indexAllOf: function(myArray, searchTerm, property) {
var ai = [];
for (var i = 0; i < myArray.length; i++) {
if (myArray[i][property] === searchTerm) ai.push(i);
}
return ai;
},
lookup: function(myArray, searchTerm, property, firstOnly) {
var found = [];
var i = myArray.length;
while (i--) {
if (myArray[i][property] === searchTerm) {
found.push(myArray[i]);
if (firstOnly) break; //if only the first
}
}
return found;
},
lookupAll: function(myArray, searchTerm, property) {
return this.lookup(myArray, searchTerm, property, false);
},
remove: function(myArray, searchTerm, property, firstOnly) {
for (var i = myArray.length - 1; i >= 0; i--) {
if (myArray[i][property] === searchTerm) {
myArray.splice(i, 1);
if (firstOnly) break; //if only the first term has to be removed
}
}
},
removeByIndex: function(myArray, index) {
myArray.splice(index, 1);
}
};
myApp.func = {
hasDuplicates: function(actor) {
var allLast = myApp.arrayObj.lookup(myApp.data.actors, actor.lName, "lName", false);
var allFirst = myApp.arrayObj.lookup(allLast, actor.fName, "fName", true);
return !!allFirst.length;
},
appendActorRow: function(newActor) {
myApp.data.actorsTable.append("<tr><td><a href='' class='update' data-actorid='" + newActor.actorId + "'>" + newActor.fName + " " + newActor.lName + "</a></td></tr>");
},
getActor: function() {
var newActor = {
fName: $("#fName").val(),
lName: $("#lName").val(),
gender: $("input[type=radio][name='gender']:checked").val(),
birthDate: $("#birthDate").val(),
action: $("#action").prop('checked'),
comedy: $("#comedy").prop('checked'),
drama: $("#drama").prop('checked'),
suspense: $("#suspense").prop('checked'),
sciencefiction: $("#sciencefiction").prop('checked'),
horror: $("#horror").prop('checked'),
actorId: $("#fName").data('actorid')
}
return newActor;
},
putActor: function(actor) {
$("#fName").val(actor.fName);
$("#lName").val(actor.lName);
$("input[type=radio][name='gender']").val(actor.gender);
$("#birthDate").val(actor.birthDate);
$("#action").prop('checked', actor.action);
$("#comedy").prop('checked', actor.comedy);
$("#drama").prop('checked', actor.drama);
$("#suspense").prop('checked', actor.suspense);
$("#sciencefiction").prop('checked', actor.sciencefiction);
$("#horror").prop('checked', actor.horror);
$("#fName").data('actorid', actor.actorId);
},
addActor: function(allowDuplicates) {
var newActor = myApp.func.getActor();
var validActor = false;
if (!allowDuplicates && !myApp.func.hasDuplicates(newActor)) {
validActor = true;
}
if (!validActor && allowDuplicates) {
validActor = true;
}
if (validActor) {
myApp.data.lastActorId = myApp.data.lastActorId + 1;
newActor.actorId = myApp.data.lastActorId;
myApp.func.appendActorRow(newActor);
myApp.data.actors.push(newActor);
}
return newActor;
},
updateRowByIndex: function(actor, index) {
myApp.data.actorsTable.eq(index).html(actor.fName + " " + actor.lName).data("actorid", actor.actorId).addClass('update');
},
updateRowByActorId: function(actor, actorId) {
var r = myApp.data.actorsTable.find('a[data-actorid="' + actorId + '"]');
r.html(actor.fName + " " + actor.lName).data("actorid", actor.actorId).addClass('update');
},
clearForm: function() {
$('#fName').val("");
$('#lName').val("");
$('#birthDate').val("");
$('#form').find('input[type="checkbox"]').prop("checked", false);
$('#form').find('input[type="radio"]').prop("checked", false);
return this;
},
selectActor: function(e) {
e.preventDefault();
var selectActorId = $(this).data('actorid');
var actor = myApp.arrayObj.lookup(myApp.data.actors, selectActorId, "actorId", true)[0];
myApp.func.putActor(actor);
myApp.func.setButtons("old")
},
updateActor: function() {
var actor = myApp.func.getActor();
var index = myApp.arrayObj.indexOf(myApp.data.actors, actor.actorId, "actorId", true);
if (index != -1) {
myApp.data.actors[index] = actor;
myApp.func.updateRowByActorId(actor, actor.actorId);
}
},
deleteActor: function() {
var actor = myApp.func.getActor();
var index = myApp.arrayObj.indexOf(myApp.data.actors, actor.actorId, "actorId", true);
if (index != -1) {
var r = myApp.data.actorsTable.find('a[data-actorid="' + actor.actorId + '"]');
r.parents('tr').remove();
// either will work, used the index one
// myApp.arrayObj.remove(myApp.data.actors, actor.actorId, "actorId", true);
myApp.arrayObj.removeByIndex(myApp.data.actors, index);
}
myApp.func.clearForm().setButtons("new");
// myApp.func.setButtons("new");
},
setButtons: function(foo) {
// if page is new only or form is being filled with new data
// show 'Add Actor' button only
$("#addNewActor").toggle((foo === "new"));
$("#updateActor").toggle(!(foo === "new"));
$("#deleteActor").toggle(!(foo === "new"));
}
};
myApp.data = {
actors: [],
actorsTable: $("#actorsTable"),
lastActorId: 0
};
/* end of myApp */
// Function checks state of page and shows/hides buttons
var actorStatex = function(foo) {
// if page is new only or form is being filled with new data
// show 'Add Actor' button only
$("#addNewActor").toggle((foo === "new"));
$("#updateActor").toggle(!(foo === "new"));
$("#deleteActor").toggle(!(foo === "new"));
};
var validateForm = function(e) {};
$(document).ready(function() {
$('#results').on('click', '.update', myApp.func.selectActor);
$("#birthDate").datepicker();
myApp.func.setButtons("new");
$("#addNewActor").on('click', function() {
var addedActor = myApp.func.addActor(false);
});
$("#updateActor").on('click', myApp.func.updateActor);
$("#deleteActor").on('click', myApp.func.deleteActor);
$("#clearButton").on('click', function() {
myApp.func.clearForm();
myApp.func.setButtons("new");
});
});
it's because the names of your attributes in your alert doesn't match with those in your newActor object.
You should use alert(actors[row].fName) instead of alert(actors[row].fname)
By the way you could make it really simplier using your form id #actorForm
It should be something like this (I have not tested)
var actors = [], index = 0;
$("#addNewActor").click(function() {
var newActor = $('#actorForm').serialize();
$("#actorsTable").append("<tr><td><a href='' class='update'>" + newActor.fName + " " + newActor.lName + "</a></td></tr> ");
actors.push(newActor);
});
// select actor
$(document).on('click', '#actorsTable tr', function() {
if(actors[$(this).index]) {
index = $(this).index();
var actor = actors[index];
// populate your form
}
});
$("#updateActor").click(function() {
var newActor = $('#actorForm').serialize();
actors[index] = newActor;
});
$("#deleteActor").click(function() {
actors.splice(index, 1);
});

Why do I get an undefined value if the value is defined? using eval()

I cant quite figure out why I am getting an undefined in my console...
Each object being iterated over has the property defined.
Where did I go wrong??
the collection looks like this:
var a = [
{
city: 'Tucson',
state: 'AR',
zipcode: 85701
},
{
city: 'Orlando',
state: 'FL',
zipcode: 32828
},
{
city: 'Apopka',
state: 'FL',
zipcode: "32703",
},
{
city: 'Compton',
state: 'CA',
zipcode: 90220
}
];
here's the function:
function reduce(collection, condition){
var map = [];
for (let v in collection){
var cl = [], r, e, matches, m;
if ('string' === typeof condition) {
r = new RegExp(/([\w]+)\s*?(?=(>|<|>=|<=|==|===|!=|!==))/g);
matches = condition.match( r );
var nm = condition;
matches.forEach(function(m, index){
// outputs state console.log(m);
nm = nm.replace(m, (collection[v][String(m)]) + ' ' );
console.dir(collection[v]);
console.dir(m + " replaced by " + collection[v][m] + ", gets you: " + nm);
});
cl.push(m);
//if (eval(condition) === true) { map.push(collection[v]); }
} else if ('object' === typeof condition){
for (let c in condition){
r = new RegExp("(" + collection[v][c] + ")*(>|<|>=|<=|==|===|!=|!==)", "g");
e = condition[c];
matches = condition[c].match( r );
if (0 < matches.length) {
matches.forEach(function(m, index){
if ( condition[c].indexOf(c) === -1 ) {
e = e.replace(m, ( (typeof collection[v][c] === 'string') ? "'" + collection[v][c] + "'" : collection[v][c] ) + " " + m);
}
});
};
cl.push(e);
}
if (eval(cl.join(" && ")) === true) { map.push(collection[v]); }
};
console.log(cl.join(" && "));
}
return map;
}
...
and here's the call to:
var floridians = reduce(a, "state == 'FL'");
Thanks in advance guys!
The reason you get undefined is because your variable m (which you think contains the string "state") has a trailing space. When used in the square-bracket notation to read the property of your object, this returns undefined.
This was found using good ol' fashioned debugging: https://jsfiddle.net/wLs3o9mk/ - Your use of console.dir was masking the issue, it appears to collapse multiple spaces (like HTML). It became pretty obvious when changing to console.log which does not.

Group or rearrange array elements based on a condition - javascript

I have an array called 'country' which looks like:
country=[
{
"name": "china",
"id": "country:china"
}, {
"name": "city1",
"id": "country:country1>city1"
}, {
"name": "city2",
"id": "country:country1>city2"
}, {
"name": "city3",
"id": "country:country1>city3"
}, {
"name": "korea",
"id": "country:korea"
}, {
"name": "australia",
"id": "country:australia"
}
]
I am looking at rearranging/grouping the above array as:
countryResult = [ china, country1(city1, city2, city3), korea, australia]
I have written the following code but this does not give me the desired result:
$scope.countryInfo = function(itemData){
var countryResult = [];
for(var i=0; i<itemData.length; i++){
var countryItem = itemData[i];
if(countryItem.id.indexOf('>') > -1){ //Found city
var itemId = countryItem.id.substr(0, countryItem.id.indexOf('>'));
for(var j=0; j<$scope.countryData.length; j++){
if($scope.countryData[j].id == itemId){
var _parentChild = $scope.countryData[j].name + "( " + countryItem.name + " ) ";
countryResult.push(_parentChild);
}
}
}
else{
countryResult.push(countryItem.name);
}
}
return countryResult;
}
The result is coming up like this - [ china, country1(city1), country1(city2), country1(city3)), korea, australia]
Please let me know how to achieve the expected array result.
EDIT: I am just looking at simplifying the array [ china, country1(city1), country1(city2), country1(city3)), korea, australia] to [ china, country1(city1, city2, city3), korea, australia]
I've used reduce with an initial object with a keys property to capture the positions of the elements:
function sorter(countty) {
var obj = country.reduce(function (p, c, i) {
var key, id = c.id.split(/[:>]/);
if (id.length === 3) {
key = id[1];
if (!p[key]) {
p[key] = [];
p.keys.push(key);
}
p[key].push(id[2]);
} else {
p.keys.push(c.name);
}
return p;
}, { keys: [] });
return obj.keys.map(function (el) {
return obj[el] ? el + '(' + obj[el].join(', ') + ')' : el;
});
}
sorter(country);
DEMO
You can use a temporary object and then map the object's properties to the wanted array.
var country = [{ "name": "china", "id": "country:china" }, { "name": "city1", "id": "country:country1>city1" }, { "name": "city2", "id": "country:country1>city2" }, { "name": "city3", "id": "country:country1>city3" }, { "name": "korea", "id": "country:korea" }, { "name": "australia", "id": "country:australia" }],
temp = {},
result;
country.forEach(function (a) {
var b = a.id.split(/\:|\>/g);
temp[b[1]] = temp[b[1]] || [];
if (b[2]) {
temp[b[1]].push(b[2]);
}
});
result = Object.keys(temp).map(function (k) {
if (temp[k].length) {
return k + '(' + temp[k].join(', ') + ')';
}
return k;
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
I wrote this bit of code to change your first array (in your "EDIT") into your second array, I'm not saying it's clean, but it works:
sorts the array, then tries to figure out if the countries match, and if they have cities that need to be merged...
//an array of countries, some of which include comma delimited cities wrappedin parentheses
var arrayPlaces = ["china", "country1(city1)", "korea", "country1", "country1(city2)", "country1(city3)", "australia", "korea", "home(delicious)", "home(nacho)", "home(plate)"];
//creates an alphabatized version of the array, to simplify finding matching countries
var arrayPlacesSorted = arrayPlaces.sort();
//defines a regular expression (to search for matches countries)
var hasCity = function (sTemp) {
var re = /\(/;
if (re.test(sTemp)) {
return true;
} else {
return false;
}
};
var countryRe = /(.*?)\(.*?\)/;
var cityRe = /.*?\((.*?)\)/;
//function that loops through array, checks for matching countries, combines/adds cities
var groupCities = function (aTemp) {
var currentCountry,
currentCity,
nextCountry,
nextCity;
for (var i = 0; i < (aTemp.length); i++) {
if (hasCity(aTemp[i])) {
currentCountry = countryRe.exec(aTemp[i])[1];
currentCity = cityRe.exec(aTemp[i])[1];
} else {
currentCountry = aTemp[i];
currentCity = false;
}
if (hasCity(aTemp[i + 1])) {
nextCountry = countryRe.exec(aTemp[i + 1])[1];
nextCity = cityRe.exec(aTemp[i + 1])[1];
} else {
nextCountry = aTemp[i + 1];
nextCity = false;
}
if (currentCountry === nextCountry && nextCity && currentCity) {
aTemp[i] = currentCountry + "(" + currentCity + "," + nextCity + ")";
aTemp.splice(i + 1, 1);
i = 0;
} else if (currentCountry === nextCountry && nextCity) {
aTemp[i] = currentCountry + "(" + nextCity + ")";
aTemp.splice(i + 1, 1);
i = 0;
} else if (currentCountry === nextCountry && currentCity) {
aTemp[i] = currentCountry + "(" + currentCity + ")";
aTemp.splice(i + 1, 1);
i = 0;
} else if (currentCountry === nextCountry) {
aTemp[i] = currentCountry;
aTemp.splice(i + 1, 1);
i = 0;
}
}
return aTemp;
};
var result = groupCities(arrayPlacesSorted);
console.log(result);

Categories