javascript conditions applied on independant objects - javascript

I'm going crazy for i do not understand the behavior of my loop!
here a sample of a json I read :
[{"type":"robot","town":"NANTES","region":"Ouest","performances":[{"date":YYYY-MM-DD","value":100},{...}],"availability":[{"date":"YYY-MM-DD","value":100},{...}]},{"type":"robot","town":"RENNES","region":"Ouest","performances":[{"date":YYYY-MM-DD","value":100},{...}],"availability":[{"date":"YYY-MM-DD","value":100},{...}]}
I create 2 objects :
REGIONS = {},TOWNS= {};
here is the function the moment i recieve the object:
function getRobotsDatas(robotList) {
for (var i = 0; i < robotList.length; i++) {
var robot = robotList[i];
// working on TOWNS object
//I check if the "town" object of TOWNS object already exist
if (TOWNS[robot.town] === undefined) {
// if not, i create it
TOWNS[robot.town] = {};
//then i push performances datas of my robot in my TOWNS.town object
TOWNS[robot.town].performances = robot.performances;
// the same for availability datas
TOWNS[robot.town].availability= robot.availability;
}
// then I work nearly the same way on REGIONS object.
//i check if the "region" object exist in REGIONS object. If not, i create it and add the perf+availability datas of the robot.
if (REGIONS[robot.region] === undefined) {
REGIONS[robot.region] = {};
REGIONS[robot.region].performances = robot.performances;
REGIONS[robot.region].availability= robot.availability;
}
// If the REGIONS.region already exist, i just want to add the datas of performances and availability in the already existing arrays of REGIONS.region (performances[] and availabilities[])
else {
for (var j = 0; j < robot.performances.length; j++) {
REGIONS[robot.region].performances.push(robot.performances[j]);
}
for (var k = 0; k < robot.availability.length; k++) {
REGIONS[robot.region].availability.push(robot.availability[k]);
}
}
}
The problem is that the condition for an already existing "REGIONS.region" is also applied on TOWNS. It adds values of performances and availabilities in the TOWNS objects of the robots which have the same value of the "region" attribut.
for example, in the sample i gave at the beginning, i'll find availabilities and perf datas in a new object : REGIONS.Ouest {performances:[...], availability:[...]}, but i will also find NANTES' perf an availibilities datas in RENNES' perf and availabilities arrays... and THAT, i don't want!
What's wrong with my condition / loop!???

Your code refers to 'town' but your incoming JSON has 'ville' instead.
I appreciate that this won't fix the problem, but the example should at least be correct.
The incoming JSON has two sub-objects. For each one, you test for presence in your Towns and Regions data structures. If they don't each have a matching entry, you are creating one, and then adding entries in the two further sub-objects (performances and availability).
If you don't want this in both cases, you need to test the incoming JSON appropriately.

This is a problem of variable Reference. try this simple change JSON.parse(JSON.stringify(xxx))
function getRobotsDatas(robotList) {
for (var i = 0; i < robotList.length; i++) {
var robot = robotList[i];
if (TOWNS[robot.town] === undefined) {
TOWNS[robot.town] = {};
TOWNS[robot.town].performances = JSON.parse(JSON.stringify(robot.performances));
TOWNS[robot.town].disponibilite = JSON.parse(JSON.stringify(robot.availability));
}
if (REGIONS[robot.region] === undefined) {
REGIONS[robot.region] = {};
REGIONS[robot.region].performances = robot.performances;
REGIONS[robot.region].availability= robot.availability;
}
else {
for (var j = 0; j < robot.performances.length; j++) {
REGIONS[robot.region].performances.push(robot.performances[j]);
}
for (var k = 0; k < robot.availability.length; k++) {
REGIONS[robot.region].availability.push(robot.availability[k]);
}
}
}
}
JS is funny.... :)

Related

Javascript loop push into global array

1.I want to push id[i] into global array.After I pushed then it will be id.length numbers items in each array,but it will be error and says y is not a function.how to solve it?
2.the sendrequest in the bottom will send a xmlhttprequest to server,but I don't understand why it will run first and then the function(parResponse) will be fire after tmpReadRequest.sendReadRequest(); has down.
Thanks a lot
var tes0=new Array();
var tes1=new Array();
var tes2=new Array();
var tes4=new Array();
var tes5=new Array();
function ReadValuePath(id, Variable,id_2) {
var tmpReadCB = function(parResponse)
{
for (var tmpIndex = 0; tmpIndex < parResponse.length; tmpIndex++)
{
var tmpItemValue = parResponse[tmpIndex];//console.log(tmpItemValue);
var tmpValue = (tmpItemValue.mItemValue) ? tmpItemValue.mItemValue : tmpItemValue.mItemResultId;
if(document.getElementById(id[tmpIndex]) != null && document.getElementById(id_2[tmpIndex]).value != 0)
{
document.getElementById(id[tmpIndex]).value = parseFloat(tmpValue).toFixed(2);
}
}
return true;
}
var tmpReadRequest = new OPCReadRequest("DE", tmpReadCB);
for(var z=0;z<5;z++ ){
for(var i = 0; i < id.length; i++)
var y="tes"+z;
y.push(id[i]);
tmpReadRequest.addItem("ab", Variable[i]);
}
}
tmpReadRequest.sendReadRequest();
}
"A variable declared outside a function, becomes GLOBAL.
A global variable has global scope: All scripts and functions on a web page can access it. " # Source
Y is not an array so .push() won't work on it. # Source
To access the global scope through a string literal like you are trying you can use the window object which is the current global scope.
So in your case it would be window[y].push(id[i]);
Another option would be to change you scructure slightly as personally i don't like accessing the window directly.
so you could define your arrays like
var arrays = {
tes0: [],
tes2: [],
tes3: [],
tes4: [],
tes5: [],
}
and access them like:
arrays[y].push(id[i])
EDIT according to comments
So you want to access global variable in a loop. You are half way there. What your doing is building a string y which contains the property name then using that in the square brackets to access that property.
So with the window option that would be:
for(var z=0;z<5;z++ ){
var y="tes"+z;
for(var i = 0; i < id.length; i++)
window[y].push(id[i]);
}
}
or with the second object option
/*
Because arrays is an object we can use Object.keys
This will return an array of the keys in our object which we can loop over to access each one
*/
Object.keys(arrays).forEach(function(key) {
for(var i = 0; i < id.length; i++)
arrays[key].push(id[i]);
}
});
Hope that helps explain

My update tag function here isn't working

Hi all I am new to angular and would like to know what I am doing wrong in this function.
I am trying to retrieve a firebase child array of tags and compare it with users tags and get an union and post that union back to the firebase array .
Here is my function:
//this retrieved the tag arrays from firebase
$scope.utags = Tag.gettag();
This function converts a firebase array to a JS array .. I initialize it with {{universaltags(utags)}} from the view. Any attempt to initiate the function in the controller using $scope.unversaltags($scope.utags); gives me a blank array
but it works with the views initiation.
$scope.universaltags = function(utag){
var arr1 = [];
for (var i = 0 ; i < utag.length; i++) {
arr1.push(utag[i].$value);
}
return arr1;
};
Also this is the function which I use to find the union and post it back to firebase.
$scope.universaltagupdate = function union_arrays (x,y,Tag) {
var obj = {};
for (var i = x.length-1; i >= 0; -- i) {
obj[x[i]] = x[i];
}
for (var i = y.length-1; i >= 0; -- i) {
obj[y[i]] = y[i];
}
var res = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) { // <-- optional
res.push(obj[k]);
}
}
//this uses a service to set firebase value
return Tag.updatetag(res);
}
I am not able to initialize both the functions within the controller.
Can you please tell me what is wrong with this approach and what can be the best way to achieve the result? Right now using the functions in curly braces show the results, but how do I accomplish this in the controller?

JS code returning error

I'm new to JS and i had to use it for Cloud Code Parse feature. I have a class called "user_picture", through the code i query all the objects and go through it's "City" attribute. i want the response to be an array of unique city names. Anyway, here is the code i'm working on:
Parse.Cloud.define("cities", function(request, response) {
var query = new Parse.Query("user_picture");
query.find({
success: function(results) {
var cities = new Array();
for (var object in results){
var tempArray = [object.get("city")];
if (cities.length > 0){
for (var i = 0; i < cities.length; i++){
if (cities[i].get("city") == object.get("city")) {
break;
} else if (i == cities.length-1) {
cities = cities.concat(tempArray);
}
}
}
}
response.success (cities);
}, error: function() {
response.error("Error");
}
});});
However, when i run this function i receive the following error:
Error: TypeError: Object 0 has no method 'get'
at query.find.success (main.js:15:30)
at Parse.js:2:5786
at r (Parse.js:2:4981)
at Parse.js:2:4531
at Array.forEach (native)
at Object.E.each.E.forEach [as _arrayEach] (Parse.js:1:666)
at n.extend.resolve (Parse.js:2:4482)
at r (Parse.js:2:5117)
at Parse.js:2:4531
at Array.forEach (native) (Code: 141, Version: 1.2.18)
And the response returns null. I tried printing one object from the results array in order to make sure i'm receiving the right query, and it's printing fine the city. What could be the problem?
The for in loop iterates through all the keys of an object literal. Since results is an Array it will iterate through the keys of the Array, which are '0', '1' etc.
This means that the object variable will hold those key vales. And since they are not objects they don't have a method called get.
You need a forEach loop instead.
results.forEach(function(object){
var tempArray = [object.get("city")];
if (cities.length > 0){
for (var i = 0; i < cities.length; i++){
if (cities[i].get("city") == object.get("city")) {
break;
} else if (i == cities.length-1) {
cities = cities.concat(tempArray);
}
}
}
}
});
Or if you're targeting ES3 then you should use a for loop
for(var i = 0, length = results.length; i< length; i++){
var object = results[i];
var tempArray = [object.get("city")];
if (cities.length > 0){
for (var i = 0; i < cities.length; i++){
if (cities[i].get("city") == object.get("city")) {
break;
} else if (i == cities.length-1) {
cities = cities.concat(tempArray);
}
}
}
}
I recall working with Parse objects a bit and there seemed to be times to access them as an object (by direct parameter access) and sometimes by using the get method and it looks like you're mixing up the array access and object (from Parse) access methods.
Also, your list generator doesn't seem like it's really building a unique list. You only check to see if the current city is the same as the city you're going to add.
I might do something more like this (for the success method):
function(parseResults) {
var cities = {};
var ii=0;
var nResults = parseResults.length
for(;ii<nResults;++ii) {
cities[result.get('city')] = 1
}
var citiesArray = cities.keys();
response.success(citiesArray);
}
What we do here is build up an object whose keys are city names. Then return the keys as an array. What this does for us is automatically build a unique list because object keys should be unique.
If the result.get gives you problems, try replacing it with result.city. But i suspect the error you were seeing with your first example was trying to call get on the Array element.

Why do the arrays I'm creating within my loop not contain all the values I've added after the loop completes?

I have an array in Java Script that I'm trying to split into two arrays using a test within a loop. The console is logging that the two objects are being stored, but after the loop finishes the inhaledArray array only contains one object.
for (var i=0; i<results.length; i++)
{
var inhaledArray = new Array();
var otherArray = new Array();
if(results[i].get('MedicationType') == "inhaled")
{
//inhaledArray is dumping results
console.log(results[i]);
inhaledArray.push(results[i]);
}
if(results[i].get('MedicationType') == "other")
{
otherArray.push(results[i]);
}
}
You are resetting the output at every iteration (by pointing the variable to a new array).
Move the array setup code outside of the loop.
Alex already answered your question, but here's a suggestion. If you ever have a bunch of arrays that store basically the same data, consider using an object instead:
var categories = {};
for (var i = 0; i < results.length; i++) {
var name = results[i].get('MedicationType');
if (name in categories) {
categories[name].push(results[i]);
} else {
categories[name] = [results[i]];
}
}
console.log(categories.inhaled);
console.log(categories.other);
That way, you can account for all of the category types without hard-coding anything.
this is because you are initializing the array inside the forloop, just move the Array initialization before the for loop like below
var inhaledArray = new Array();
var otherArray = new Array();
for (var i = 0; i < results.length; i++) {
if (results[i].get('MedicationType') == "inhaled") {
//inhaledArray is dumping results
console.log(results[i]);
inhaledArray.push(results[i]);
}
if (results[i].get('MedicationType') == "other") {
otherArray.push(results[i]);
}
}

Javascript - clearing duplicates from an array object

Hi
I have a javascript array object rapresenting the amount of items sold in a given country, like this:
var data = [{'c1':'USA', 'c2':'Item1', 'c3':100},
{'c1':'Canada', 'c2':'Item1', 'c3':120},
{'c1':'Italy', 'c2':'Item2', 'c3':140},
{'c1':'Italy', 'c2':'Item2', 'c3':110}]
I need to avoid duplicates (as you may see, the last two 'records' have the same Country and the same Item) and sum the amounts; if I was getting data from a database I would use the DISTINCT SUM clause, but what about it in this scenario? Is there any good jquery trick?
You could use an object as a map of distinct values, like this:
var distincts, index, sum, entry, key;
distincts = {};
sum = 0;
for (index = 0; index < data.length; ++index) {
entry = data[index];
key = entry.c1 + "--sep--" + entry.c2;
if (!distincts[key]) {
distincts[key] = true;
sum += entry.c3;
}
}
How that works: JavaScript objects are maps, and since access to properties is an extremely common operation, a decent JavaScript implementation tries to make property access quite fast (by using hashing on property keys, that sort of thing). You can access object properties using a string for their name, by using brackets ([]), so obj.foo and obj["foo"] both refer to the foo property of obj.
And so:
We start with an object with no properties.
As we loop through the array, we create unique key from c1 and c2. It's important that the "--sep--" string be something that cannot appear in c1 or c2. If case isn't significant, you might throw a .toLowerCase in there.
If distincts already has a value for that key, we know we've seen it before and we can ignore it; otherwise, we add a value (true in this case, but it can be just about anything other than false, undefined, 0, or "") as a flag indicating we've seen this unique combination before. And we add c3 to the sum.
But as someone pointed out, your last two entries aren't actually the same; I'm guessing that was just a typo in the question...
jQuery may have an array function for this, but because your two Italy objects are not distinctly unique, your asking for a custom solution. You want to populate a array and check it for duplicates as you go:
var data = [{'c1':'USA', 'c2':'Item1', 'c3':100},
{'c1':'Canada', 'c2':'Item1', 'c3':120},
{'c1':'Italy', 'c2':'Item2', 'c3':140},
{'c1':'Italy', 'c2':'Item1', 'c3':110}]
var newArray = [];
var dupeCheck = {}; // hash map
for(var i=0; i < data.length; i++){
if(!dupeCheck[data[i].c1]){
newArray.push(data[i]);
dupeCheck[data[i].c1] = true;
}
}
test
HTML:
<div id="test"></div>
JS:
var data = [{'c1':'USA', 'c2':'Item1', 'c3':100},
{'c1':'Canada', 'c2':'Item1', 'c3':120},
{'c1':'Italy', 'c2':'Item2', 'c3':140},
{'c1':'Italy', 'c2':'Item1', 'c3':110}];
var
l = data.length, // length
f = "", // find
ix = "", // index
d = []; // delete
for (var i = 0; i < l; i++) {
ix = data[i].c1 + "_" + data[i].c2 + "__";
//var re = new RegExp(ix);
//if (re.test(f))
if (f.indexOf(ix) != -1)
d.push(i);
else
f += ix;
}
for (var i1 = 0; i1 < d.length; i1++){
$("#test").append("<div>for delete: "+d[i1]+"</div>");
}
EDIT
Although chrome works much faster, works only in chrome faster the example with indexOf, then in IE/Opera/Firefox/Safary works faster with an object.
The code created by "# TJ Crowder" is much more efficient.

Categories

Resources