getting javascript error while iterating through array - javascript

function sortproducts(filprodlist)
{
var prod;
var k = 0;
for (i = 0; i < filprodlist.length; i++) {
var k = i + 1;
var p=filprodlist[i].EntityKey.substr(filprodlist[i].EntityKey.length - 1);
var p2=filprodlist[k].EntityKey.substr(filprodlist[k].EntityKey.length - 1);
if ( p>p2) {
temp = filprodlist[k];
filprodlist[k] = filprodlist[i];
filprodlist[i] = temp;
}
}
rederProduct(filprodlist);
}
while executing above code getting following error
TypeError: filprodlist[k] is undefined

Reason
On last iteration, when i is at last element of array. You are fetching are using var k = i + 1;, where k doesn't exists. Thus you are getting the error.
So Use
for (i = 0; i < filprodlist.length - 1; i++) {
instead of
for (i = 0; i < filprodlist.length; i++) {

Don't var inside loops, blocks don't have scope in JavaScript, var every variable you want to use in one var statement. End your loop when the highest index reaches the end (k). You can move k into the for's iterate step because you're really iterating with this, too.
function sortproducts(filprodlist) {
var prod, i, k, p, p2, temp;
for (i = 0, k = 1; k < filprodlist.length; ++i, ++k) {
p = filprodlist[i].EntityKey.substr(filprodlist[i].EntityKey.length - 1);
p2 = filprodlist[k].EntityKey.substr(filprodlist[k].EntityKey.length - 1);
if (p > p2) {
temp = filprodlist[k];
filprodlist[k] = filprodlist[i];
filprodlist[i] = temp;
}
}
rederProduct(filprodlist);
}
A different way to do it is forget k all together, start from i = 1 and use i - 1 and i, this means you're iterating with less variables so it might be easier for you to follow the code in your mind.

Let's say filprodlist has 10 items. Then the items are indexed 0-9 and Your i goes through 0-9. In every iteration You define k = i + 1. So in the last iteration i = 9, k = 10 and You are trying to access filprodlist[10] which doesn't exist (returns undefined). Solution is in #Satpal's answer.

Related

Is there any leak in my code, Only 1 case isn't working I don't know why?

I am trying to write a programme to move all the zeroes at the end of the array and retain and the original order of other elements.
Here is my code:-
var moveZeros = function (arr) {
// TODO: Program me
var k=0;
for (var i=0;i<=arr.length-1;i++){
var s=arr[i];
if (s===0){
arr.splice(i,1);
k++
}
}
for (var j=0;j<=k-1;j++){
arr.push(0);
}
return arr
}
But when zeros are next to each other like [1,0,0,1] it doesn't work.
I don't see why.
Can anybody tell?
And please also explain why k-1 not k I wrote k-1 by observing the output.
Please don't tell the answer to the original problem I just want to fix the problem with my code. :)
The problem is that in each loop you increase the i variable by one. Meaning, you go to the next index. But if you have 2 or more zeros in the row, and you remove the first one, you shouldn't change i to i + 1, because i already points at a new value in the array(which is zero) :)
var moveZeros = function (arr) {
// TODO: Program me
var k = 0;
for (var i = 0; i <= arr.length - 1;) {
var s = arr[i];
if (s === 0) {
arr.splice(i, 1);
k++;
} else {
i++;
}
}
for (var j = 0; j <= k - 1; j++) {
arr.push(0);
}
return arr;
};
console.log(moveZeros([1,0,0,2]));

Reassigning Lists in For Loops (JavaScript)

Apologies if this has been asked before - I couldn't find what I was looking for after a search, but I'm a beginner, so I might have missed something.
I am trying to implement Lloyd's algorithm in JavaScript (very crudely) to get some practice.
var k_means = function (array,number_clusters,max_loops) {
var initial_centers = underscore.sample(shelter_lat_lon,number_clusters);
var current_centers = initial_centers;
var current_associations = {};
for (p = 0; p < current_centers.length; p++) {
current_associations[current_centers[p]] = []
}
for (loops = 0; loops < max_loops; loops++) {
for (i = 0; i < array.length; i++) {
var current_loc = array[i]
temp_array = new Array();
for (j = 0; j < current_centers.length; j++) {
var distance_from_center = distance(current_centers[j],current_loc)
temp_array.push(distance_from_center)
}
var closest_center_lat_lon = current_centers[smallest_index(temp_array)]
current_associations[closest_center_lat_lon].push(current_loc)
}
new_clusters_temp = []
for (var key in current_associations) {
lat = []
lon = []
for (i = 0; i < current_associations[key].length; i++){
lat.push(current_associations[key][i][0])
lon.push(current_associations[key][i][1])
}
mean_lat = math_module.mean(lat)
mean_lon = math_module.mean(lon)
new_clusters_temp.push([mean_lat,mean_lon])
}
current_centers = new_clusters_temp;
}
}
Sorry for the ugly code. There are 2 module requirements - underscore and mathjs (mathjs is called math_module). Additionally, the function distance returns the Euclidean distance (I'm using 2 dimensional data), and smallest_index returns the index of the smallest element in an array.
The only problem I'm having is coming at the line
current_centers = new_clusters_temp;
Node returns the error "Cannot read property 'push' of undefined." After debugging a bit, it essentially thinks the array "current_centers" is empty. In Python, this is how I would reassign a list outside of a for loop. Is this different in JavaScript?
Cheers!
Alex

Conversion of for loops to "for each"

Have been stuck on this for a while:
I tried converting the code below to for each statements,and i ended up with errors.
ChartClass.prototype.dataTranslatorLine = function(data) {
jsonLength = Object.keys(data).length;
for (j = 0; j < jsonLength; j += 2) {
var innerObjArray = new Array();
positionNumber = Object.keys(data[j].position).length;
for (k = 0; k < positionNumber; k++) {
var obj = {};
obj.x = data[j].position[k];
obj.y = data[j + 1].position[k];
innerObjArray.push(obj);
}
dataArray.push(innerObjArray);
}
return dataArray;
};
Can anyone help me out with this?
Check out my fiddle here
I'm not entirely sure what is going on, but this should be a pretty direct translation to using forEach.
ChartClass.prototype.dataTranslatorLine = function(data) {
var dataArray = [];
Object.keys(data).forEach(function(key, idx) {
if (idx % 2 === 1) {
return;
}
var innerObjArray = [];
Object.keys(data[idx].position).forEach(function(key2, idx2) {
var obj = {
x: data[idx].position[idx2],
y: data[idx + 1].position[idx2]
};
innerObjArray.push(obj);
});
dataArray.push(innerObjArray);
});
return dataArray;
};
A couple of notes though: if data is an array, there is no need to call Object.keys on it, just go directly for the iteration; this code is rather convoluted, and I would think that with some work on the data structure being passed in could make more sense; and a for loop may be better for you situation instead of the forEach loop since you are primarily working on index instead of doing stuff just with the values.
EDIT:
After looking at your data structure this is a quick and dirty way to do it, but I still suggest you rework how you are storing your data into something that makes more sense.
ChartClass.prototype.dataTranslatorLine = function(data) {
for (var i = 0; i < data.length; i += 2) {
x = data[i].position;
y = data[i + 1].position;
var innerObj = [];
for (var j = 0; j < x.length; j++) {
innerObjArray.push({
x: x[j],
y: y[j]
});
}
dataArray.push(innerObj);
}
return dataArray;
};
The forEach doesn't buy you anything since you are working with indexes, not just the contents of the array. As for what key is in Object.keys(data).forEach(function(key, idx) { for you it will be the strings 'name' and 'position' since you are iterating over the keys of the object. Also, if (idx % 2 === 1) { return; } is how it is mimicking the j += 2 from your original for loop, basically exiting the function if it is an odd index.

How to loop an Array, and to get each time the next 3?

I have an array of objects like this one - [{first},{second},{third},{forth},{fifth},{sixth}}
How can I loop through the Array, and get (for each loop) the next three elements of that Array ?
For example, for the first loop I'll get three variables that reference to {first}, {second} and {third}, for the second loop I'll get variables that reference to {forth}, {fifth} and {sixth} ...
And so on...
for (i = 0; i < arr.length; i += 3) {
var a = arr[i];
var b = arr[i + 1];
var c = arr[i + 2];
...
}
This may work:
var array = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'];
for(i = 0; i < array.length; i+=3){
var first = array[i];
var second = (array[i+1]) ? array[i+1] : null;
var third = (array[i+2]) ? array[i+2] : null;
}
If the index does not exist in the array, the variable will be null.
Fiddle
Another version of the accepted answer is:
var i = 0, len = arr.length;
while (i < len) {
var a = arr[i++];
var b = arr[i++];
var c = arr[i++];
...
}
If the array is sparse, or length is not an even multiple of 3, you may want to test that elements exist before reading their value and take that into consideration when incrementing the counter.
Try this:
var i, j;
for (i = 0; i < 4; i += 1) {
// Loop
}
for (j = i; j < arr.length; j += 1) {
// Second loop
}
Just add 1 for the element after i, and add 2 for the element that comes after that.
var ary1,ary2,ary3;
for(var i=0;i<size-3;i+=3){
ary1 = myary[i];
ary2 = myary[i+1];
ary3 = myary[i+2];
}
This is really pretty basic
var array; // your array (let's pretend it's already populated)
for (i = 0; i < array.length - 3; i += 3) {
element1 = array[i];
element2 = array[i+1];
element3 = array[i+2];
}
I didn't put in handling for cases where you don't have exactly a multiple of three objects in the array, but this should get you started.

Using .set on a filtered array of IDs in backbone

I used Underscore.js's _.filter to get an array of object ids like so:
var downstreamMeters = _.filter(that.collection.models, function(item) { return item.get("isdownstreammeter"); });
Now I want to set a certain attribute of each model in the array. I thought it would make sense to do this:
for (var i = 0; i < downstreamMeters.length; i++) {
var sum = 0;
inputMeters = downstreamMeters[i].get("inputmeters");
for (var i = 0; i < inputMeters.length; i++) {
var flow = parseFloat(that.collection.get(inputMeters[i]).get("adjustedflow"));
sum += flow;
}
downstreamMeters[i].set({incrementalflow: sum});
}
However, I get the error:
Uncaught TypeError: Cannot call method 'set' of undefined
I checked the downstreamMeters array and it has the right objects in it. What do I need to do to set the attribute for each model in the array?
Saying for(var i = 0; ...) is somewhat misleading. JavaScript hoists all var declarations up to the top of the closest scope and for loop doesn't create its own scope. The result is that this:
for (var i = 0; i < downstreamMeters.length; i++) {
var sum = 0;
inputMeters = downstreamMeters[i].get("inputmeters");
for (var i = 0; i < inputMeters.length; i++) {
var flow = parseFloat(that.collection.get(inputMeters[i]).get("adjustedflow"));
sum += flow;
}
downstreamMeters[i].set({incrementalflow: sum});
}
is the same as this:
var i, sum, flow;
for (i = 0; i < downstreamMeters.length; i++) {
sum = 0;
inputMeters = downstreamMeters[i].get("inputmeters");
for (i = 0; i < inputMeters.length; i++) {
flow = parseFloat(that.collection.get(inputMeters[i]).get("adjustedflow"));
sum += flow;
}
downstreamMeters[i].set({incrementalflow: sum});
}
Now you can see that you are using exactly the same i in the outer and inner loops. On the first run through the loop, i will be inputMeters.length when you say downstreamMeters[i].set(...). Apparently, inputMeters.length > downstreamMeters.length so you end up running off the end of downstreamMeters; if you try to access an element of an array that is past the array's end, you get undefined and there's your
Cannot call method 'set' of undefined.
error.
Nesting loops is fine but you should be using different variables:
var i, j, sum, inputMeters;
for (i = 0; i < downstreamMeters.length; i++) {
sum = 0;
inputMeters = downstreamMeters[i].get("inputmeters");
for (j = 0; j < inputMeters.length; j++)
sum += parseFloat(that.collection.get(inputMeters[j]).get("adjustedflow"));
downstreamMeters[i].set({incrementalflow: sum});
}

Categories

Resources