Better way to transform a collection using underscorejs - javascript

I'm trying to simply replace the invalid date with an empty string. I'm iterating through an array of objects, but whenever I try to use _.each() I get lost. If someone could show me a way to iterate through all the fieldsToCheck items in my list, that would be rad.
massage.removeBadDates = function(data){
var fieldsToCheck = [
"partsLeadTime",
"statusDate",
"targetDate",
"revisedTargetDate",
"quoteDate",
"dispositionDate",
"serviceDate",
"finalDate",
"receivedDate"]
var newData = []
_.map(data, function(value, index, list){
newData.push(value)
//single
if (list[index].partsLeadTime == "1900-01-01T00:00:00"){
newData[index].partsLeadTime = ""
}
});
return newData
};

You pretty much want something like this:
_.each(fieldsToCheck(function(field) {
if (list[index][field] == "1900-01-01T00:00:00") {
newData[index][field] = ""
}
});

Related

Array of objects filter issue

I have got the following JSON as an array and I am trying to filter on roles attribute but I am not able to filter the results. Please help me.
var data = [{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["CitySupervisor"]},{"roles":["citysupervisor"]},{"roles":["partner"]},{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["clientsupervisor"]}];
The JavaScript code which I wrote is below:
var results = data.filter(function(user) {
var roles = user.roles;
return roles.filter(function(role) {
return role == 'clientsupervisor';
});
});
Your data variable has a syntax error. You need to remove the quotes that are wrapping it.
Also a little change in your filtering code.
Change from this:
"[{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["CitySupervisor"]},{"roles":["citysupervisor"]},{"roles":["partner"]},{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["clientsupervisor"]}]";
To this:
[{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["CitySupervisor"]},{"roles":["citysupervisor"]},{"roles":["partner"]},{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["clientsupervisor"]}];
See it working:
var data = [{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["CitySupervisor"]},{"roles":["citysupervisor"]},{"roles":["partner"]},{"roles":["citysupervisor"]},{"roles":["partner","supervisor"]},{"roles":["clientsupervisor"], "name": "Jack", "profileId": 34533}];
var results = data.filter(function (user){
return user.roles.indexOf('clientsupervisor') > -1;
});
console.log(results);
try this, simple way
var results = data.filter(function(user) {
return user.roles.indexOf("clientsupervisor") > -1 ? true: false
});
and remove "" from data object, this is array object
var data = [{"roles":["citysupervisor"]},.....];

Trying to iterate over json string

I'm trying to iterate over this json encoded array which is a string:
"{"":{"count":{"total":112,"open":0,
"solved":0,
"deleted":106,
"closed":6},
"average_time_open_in_minutes":206,
"tickets_fortnight_week_count":11,
"tickets_last_week_count":15,"trend":1},
"Net2grid":{"count":"total":8,"open":0,"solved":0,"deleted":8},"average_time_open_in_minutes":0,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0},"Closed_by_merge":{"count":{"total":2,"open":0,"solved":0,"closed":2},"average_time_open_in_minutes":502,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0},"Analytics":{"count":{"total":1,"open":0,"solved":0,"deleted":1},"average_time_open_in_minutes":26,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0},"Meter":{"count":{"total":5,"open":5,"solved":0},"average_time_open_in_minutes":0,"tickets_fortnight_week_count":0,"tickets_last_week_count":2,"trend":1},"Installation":{"count":{"total":8,"open":5,"solved":3},"average_time_open_in_minutes":404,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0},"Other...":{"count":{"total":3,"open":2,"solved":1},"average_time_open_in_minutes":39,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0},"Meter Offline":{"count":{"total":8,"open":7,"solved":1},"average_time_open_in_minutes":8,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0},"App Usage":{"count":{"total":6,"open":5,"solved":0,"deleted":1},"average_time_open_in_minutes":8,"tickets_fortnight_week_count":0,"tickets_last_week_count":0,"trend":0}}"
An ajax call returns that string and i'm trying to only get the keys like: "app usage" and "Meter Offline" to return like so:
$.get('/ajax/ticket-and-notes-data.php', function (data) {
var problems = getProblems(data);
function getProblems(problems) {
var problemCategories = [];
$.each(JSON.parse(problems), function (key, value) {
if (key != "") {
problemCategories.push = key;
}
});
return problemCategories;
}
});
But I can't get the keys to go into the problemCategories.
I use this to set the categories in a highchart bubble chart and I will use more of the data from the string later.
I need to get this to work first.
The issue is in the way that you're using array.push. You should use array.push(item) instead of array.push = item.

Access the nested value in JSON without looping through it

This is my JSON, I want to directly get the zipCodes values from the JSON without looping through the JSON. How can I do it?
countries:[
{
name:'India',
states:[{
name:'Orissa',
cities:[{
name:'Sambalpur',
zipCodes:{'768019','768020'}
}]
}]
}
]
I think you are looking for
countries[0].states[0].cities[0].zipCodes
Please note, this works for the above JSON as there is only 1 country in countries array and same as for states and cities. However, if there are more than 1 country, state or city then, you will have to iterate to extract information until and unless you know the exact index.
As this is not an associative array, your option is only to use indexes like this:
countries[x].states[y].cities[0].zipCodes
Where x would be each representation of state in your array, in case, of course, that you have more than one.
Similarly y would be each state in each state in each country, in case you have more of those and you can do the same for cities if you need to.
EDIT:
Here's how you can iterate the array:
for(var c in countries)
{
var name = countries[c].name;
if (name === "CountryIAmLookingFor")
{
var statesList = countries[c].states;
for (var s in statesList)
{
var stateName = statesList[s].name;
.....
}
}
}
You can keep iterating until you find the country, state, and city you need, then extract the zipCodes from there as shown in the previous code snippet.
Without "looping"
You can do this crazy trick (not saying this is the best way, but this way you aren't looping through the JSON):
var myData = { 'Put Your Data': 'HERE' };
function getCodes(name, data) {
var sv = data.match(new RegExp(name+'([\\S\\s]*?}][\\S\\s]*?}])'))[1].match(/zipCodes":\[(.*?)\]/g), r = [];
sv.forEach(function (item) {
item.match(/\d+/g).forEach(function (sub) {
r.push(+sub);
});
});
return r;
}
getCodes('India', JSON.stringify(myData));
If your data is already string, then you don't need the JSON.stringify. The forEach you see isn't actually "looping" through the JSON. It's already extracted the zip codes and the code just adds the zip codes to the array. . This line:
var sv = JSON.stringify(data).match(new RegExp(name+'([\\S\\s]*?}][\\S\\s]*?}])'))[1].match(/zipCodes":\[(.*?)\]/g), r = [];
is what grabs the zip codes, it gets something like:
["zipCodes":["768019","768020"]"]
The next line:
item.match(/\d+/g)
will grab the numbers outputting something like:
["768019", "768020"]
The loop just adds the zip-codes to another array
With looping
You're better off looping through the JSON:
var myData = {}, // Your data
zips = [];
myData.countries.forEach(function(i) {
if (i.name === 'India') {
i.states.forEach(function(j) {
j.cities.forEach(function(l) {
l.zipCodes.forEach(function(m) {
zips.push(m);
});
});
});
}
});
//use "zips" array
PERFORMANCE AND SPEED TESTS
After testing copying an array about 500MB (half a gig) took about 30 seconds. That's a lot. Considering an extremely large JSON would be about ~5MB, looping through a little over 5MB of JSON takes about 0.14 seconds. You should never worry about speed.
Here's my "trick" for avoiding explicit iteration. Let JSON.parse or JSON.stringify do the work for you. If your JSON is in string form, try this:
var array = [];
JSON.parse(jsonString, function (key, value) {
if (key === "zipCodes") {
array = array.concat(value);
}
return value;
});
console.log(array); // all your zipCodes
Suppose your Json is like
countries =[
{
name:'India',
states:[{
name:'Orissa',
cities:[{
name:'Sambalpur',
zipCodes:768019768020
}]
},{
name:'mumbai',
cities:[{
name:'rea',
zipCodes:324243
}]
}]
}
]
So now we use MAP it will give you ZipCode of every cities
countries.map(function(s){
s.states.map(function(c){
c.cities.map(function(z){
console.log(z.zipCodes)
})
})
})
OR
If you use return statement then it will give you 2 array with two zip code as per over JSON
var finalOP = countries.map(function(s){
var Stalist = s.states.map(function(c){
var zip = c.cities.map(function(z){
return z.zipCodes
})
return zip
})
return Stalist
})
console.log(finalOP)

refactor two $.each() loops to one

I have a JSON object like this...
{
"tasks":[
{
"id":"task_3",
"taskName":"Task A",
"assignee":"Barrack Obama",
"timeReqOptimisitic":"4",
"timeReqNormal":"8",
"timeReqPessimistic":"14",
"timeUnit":"Days",
"timeReq":"8.33",
"positionX":493,
"positionY":101,
"lockStatus":"unlocked"
}
],
"milestones":[
{
"id":"task_1",
"milestoneName":"Start",
"positionX":149,
"positionY":109,
"lockStatus":"unlocked",
"milestoneDate":"2015-04-07"
},
{
"id":"task_2",
"milestoneName":"Finish",
"positionX":989,
"positionY":367,
"lockStatus":"unlocked",
"milestoneDate":"2015-04-22"
}
],
"connections":[
{
"connectionId":"con_10",
"pageSourceId":"task_1",
"pageTargetId":"task_3"
},
{
"connectionId":"con_20",
"pageSourceId":"task_3",
"pageTargetId":"task_2"
}
]
}
...this is a minimal version. In practice, there are numerous items in "tasks", "milestones" and "connections".
I need to iterate through the object and determine the "id" of the "milestones" item with the lowest/earliest "milestoneDate", then identify the "connections" item that has the same value for its "pageSourceId" and return its "pageTargetId".
So in the above example:
Step 1) Iterate through the object and determine the "id" of the "milestones" item with the lowest/earliest "milestoneDate".
Answer: milestones.id = "task_1"
Step 2) Identify the "connections" item that has the same value for its "pageSourceId".
Answer: connections.pageSourceId = "task_1"
Step 3) Return its "pageTargetId".
Answer: "task_3"
I have a working example here. However, I would like to know if there is a way to accomplish this without using the extremely high start date and also in one loop.
As you are not parsing the same array on these two loops, there is no way to merge your loops.
Anyway, you can yet remove the loops to access to the arrays:
http://jsfiddle.net/gael/sruvtwre/2/
$.each(object.milestones, function( index, value ) {
if(startDate > parseDate(value.milestoneDate)) {
startDate = parseDate(value.milestoneDate);
id = value.id
}
});
$.each(object.connections, function( index, value ) {
if(id == value.pageSourceId) {
pageTargetId = value.pageTargetId;
}
});
May be also sorting, and indexing your datas. Then you would need no loops:
Elements in milestones should be sorted, so the earliest milestones element would be milestones[0].
Elements in connections should be indexed by their pageTargetId property, so the requested element should be connections[id].
Your two loops would become:
var pageTargetId= object.connections[ object.milestones[0].id ].pageTargetId;
http://jsfiddle.net/gael/sruvtwre/4/
As said in comments, sorting is not an optimal solution, even if that does not really matter for small sets.
Roughly, there is no no needs to sort all the datas, just the latest matters.
You can use array reduce method, as an comparable alternative to a simple loop:
var latestMilestone= object.milestones.reduce(function(milestone1, milestone2){
if( parseDate(milestone1.milestoneDate) > parseDate(milestone2.milestoneDate) )
return milestone1;
else
return milestone2;
//convert date to timestamp
function parseDate(date) {
var parts = date.split('-');
return Date.UTC(parts[0], parts[1]-1, parts[2]); // Note: months are 0-based
}
});
How about this:
Assuming you get the milestones.id = "task_1" in first loop; outside the loop we can have use jQuery grep. As connections will have unique pageSourceId, grep will return an array with only one object.
var filteredData = jQuery.grep('CONNECTIONS_ARRAY', function(element, index){
return element.pageSourceId == 'MILESTONES_ID'; // Which you get in the loop earlier
});
Then we can access pageTargetId like this:
if(filteredData.length){
filteredData[0].pageTargetId;
}
Try
var dates = []
, ids = []
, filtered = $.map(data.milestones, function(value, index) {
dates.push(new Date(value.milestoneDate).getTime());
ids.push(value.id);
if (dates.length === data.milestones.length) {
var id = ids[$.inArray(Math.min.apply(Math, dates), dates)]
, res = $.grep(data.connections, function(task, key) {
return task.pageSourceId === id
})[0].pageTargetId;
return res
}
})[0]; // `"task_3"`
var data = {
"tasks":[
{
"id":"task_3",
"taskName":"Task A",
"assignee":"Barrack Obama",
"timeReqOptimisitic":"4",
"timeReqNormal":"8",
"timeReqPessimistic":"14",
"timeUnit":"Days",
"timeReq":"8.33",
"positionX":493,
"positionY":101,
"lockStatus":"unlocked"
}
],
"milestones":[
{
"id":"task_1",
"milestoneName":"Start",
"positionX":149,
"positionY":109,
"lockStatus":"unlocked",
"milestoneDate":"2015-04-07"
},
{
"id":"task_2",
"milestoneName":"Finish",
"positionX":989,
"positionY":367,
"lockStatus":"unlocked",
"milestoneDate":"2015-04-22"
}
],
"connections":[
{
"connectionId":"con_10",
"pageSourceId":"task_1",
"pageTargetId":"task_3"
},
{
"connectionId":"con_20",
"pageSourceId":"task_3",
"pageTargetId":"task_2"
}
]
};
var dates = []
, ids = []
, filtered = $.map(data.milestones, function(value, index) {
dates.push(new Date(value.milestoneDate).getTime());
ids.push(value.id);
if (dates.length === data.milestones.length) {
var id = ids[$.inArray(Math.min.apply(Math, dates), dates)]
, res = $.grep(data.connections, function(task, key) {
return task.pageSourceId === id
})[0].pageTargetId;
return res
}
})[0];
document.write(filtered);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

Reconstruct JSON after duplicates have been removed

I have the following JSON -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
},
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
I have the following javascript that will remove duplicates from the node1 section -
function groupBy(items, propertyName) {
var result = [];
$.each(items, function (index, item) {
if ($.inArray(item[propertyName], result) == -1) {
result.push(item[propertyName]);
}
});
return result;
}
groupBy(catalog.node1, 'one');
However this does not account for dupicates in node2.
The resulting JSON I require is to look like -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
However I cannot get this to work and groupBy only returns a string with the duplicates removed not a restructured JSON?
You should probably look for some good implementation of a JavaScript set and use that to represent your node objects. The set data structure would ensure that you only keep unique items.
On the other hand, you may try to write your own dedup algorithm. This is one example
function dedup(data, equals){
if(data.length > 1){
return data.reduce(function(set, item){
var alreadyExist = set.some(function(unique){
return equals(unique, item);
});
if(!alreadyExist){
set.push(item)
}
return set;
},[]);
}
return [].concat(data);
}
Unfortunately, the performance of this algorithm is not too good, I think somewhat like O(n^2/2) since I check the set of unique items every time to verify if a given item exists. This won't be a big deal if your structure is really that small. But at any rate, this is where a hash-based or a tree-based algorithm would probably be better.
You can also see that I have abstracted away the definition of what is "equal". So you can provide that in a secondary function. Most likely the use of JSON.stringify is a bad idea because it takes time to serialize an object. If you can write your own customized algorithm to compare key by key that'd be probably better.
So, a naive (not recommended) implementation of equals could be somewhat like the proposed in the other answer:
var equals = function(left, right){
return JSON.stringify(left) === JSON.stringify(right);
};
And then you could simply do:
var res = Object.keys(source).reduce(function(res, key){
res[key] = dedup(source[key], equals);
return res;
},{});
Here is my version:
var obj = {} // JSON object provided in the post.
var result = Object.keys(obj);
var test = result.map(function(o){
obj[o] = obj[o].reduce(function(a,c){
if (!a.some(function(item){
return JSON.stringify(item) === JSON.stringify(c); })){
a.push(c);
}
return a;
},[]); return obj[o]; });
console.log(obj);//outputs the expected result
Using Array.prototype.reduce along with Array.prototype.some I searched for all the items being added into the new array generated into Array.prototype.reduce in the var named a by doing:
a.some(function(item){ return JSON.stringify(item) === JSON.stringify(c); })
Array.prototype.some will loop trough this new array and compare the existing items against the new item c using JSON.stringify.
Try this:
var duplicatedDataArray = [];
var DuplicatedArray = [];
//Avoiding Duplicate in Array Datas
var givenData = {givenDataForDuplication : givenArray};
$.each(givenData.givenDataForDuplication, function (index, value) {
if ($.inArray(value.ItemName, duplicatedDataArray) == -1) {
duplicatedDataArray.push(value.ItemName);
DuplicatedArray.push(value);
}
});

Categories