Using push in array with for...in... loop - javascript

I am trying to use this code in Javascript to verify prime numbers using an array to store them:
var nprimi = [2];
function verifica(x)
{
var i;
var x;
var k;
//for (k in nprimi)
for (k=0;k<nprimi.length;k++)
{
if (nprimi[k]==x)
return true;
else if (x%nprimi[k]==0)
return false;
}
for (i=k+1;i<x;i++)
{
if (x%i==0)
return false;
}
nprimi.push(x);
return true;
}
My problem is:
If I use
for (k=0;k<nprimi.length;k++)
for loop is running correctly, but using
for (k in nprimi)
doesn't work.
It seems that after each nprimi.push(x) the number of elements in objetc nprimi is always zero.
Maybe it is a very stupid error, but I am not able to find it!
Thank you very much for helping!

Ciao Giancarlo,
the short answer is: in JavaScript you do not use for..in to loop through arrays.
You use for..in to loop through objects.
A really good explanation is to be found here.
Edit:
Another thing. In your code, in the function verifica, you have an x parameter and an x local variable, you should really remove the var x declaration.
function verifica(x)
{
var i;
var x; // <-- this shouldn't be here.

It's not working because that's not what for-in is for. for-in loops through the names of enumerable object properties, not array indexes. Those names are strings, not numbers. So following your loop, k+1 will be a concatenation operation, not an addition operation. That is, if k is "2", then k+1 will be "21".
Don't use for-in to loop through arrays unless you know what you're doing and use safeguards. More about looping arrays in this answer.

In for loop after the loop the value of k will be incremented (k++). But in the case of for-in it will not happen. So in that case you have to do it manually. I have updated the function:
function verifica(x)
{
var i;
var x;
var k;
for (k in nprimi)
//for (k=0;k<nprimi.length;k++)
{
if (nprimi[k]==x)
return true;
else if (x%nprimi[k]==0)
return false;
}
k++; //This is the line making difference in for-in loop
for (i=k+1;i<x;i++) {
if (x%i==0)
return false;
}
nprimi.push(x);
return true;
}

for in iterates over the indexes of the array
var myArray = ['a', 'b', 'c'];
for (k in myArray) {
console.log(k + ' -> ' + myArray[k]);
}
outputs:
0 -> 'a'
1 -> 'b'
2 -> 'c'
As you can see, the k variable does not contain the 'a', 'b', 'c'

Related

Javascript recursive permutation generator

I'm trying to implement a recursive permutation generator in Javascript, but I can't seem to get it to go through all the recursion branches (see the Results below).
I know I'm missing something important, can someone help me understand where I've gone wrong?
var permute = function(input){
var permutation = function (arr, position){
if(position >= arr.length-1){
results.push(arr);
}else{
var tempSwap="";
for(i=position;i<arr.length;i++){
tempSwap = arr[position];
arr.splice(position,1,arr[i]);
arr.splice(i,1,tempSwap);
permutation(arr,(position+1));
}
return;
}
};
permutation(input,0);
};
var results=[];
permute(['a','b','c']);
console.log(results);
Results:
[ [ 'a', 'c', 'b' ], [ 'a', 'c', 'b' ] ]
There were two errors: you was working on the same array without making copies and your loop counter i was a global variable. Fixed code:
var permute = function(input){
var permutation = function (arr, position){
if(position == arr.length-1){ // >= was redundant and confusing
results.push(arr);
}else{
for(var i=position;i<arr.length;i++){ // use local i
var tempSwap = arr[position];
arr.splice(position,1,arr[i]);
arr.splice(i,1,tempSwap);
permutation(arr.slice(),(position+1)); // you need a copy here
}
return;
}
};
permutation(input,0);
};
var results=[];
permute(['a','b','c']);
console.log(results.join(' ')); // a,b,c a,c,b b,a,c b,c,a c,a,b c,b,a
https://jsfiddle.net/sagqkchL/1/
Not making copies caused all of your result arrays to look the same. The global variable caused only 2 results being produced.
I know I'm missing important
Your i variable is implictly global. Declare it with var, and your basic problem will go away.
Also, as mentioned in the comments, you are not copying the input array so you're always modifying the same object (and end up with result[0] == result[1] == …); you end your recursion one level too early (the base case is when you've met the end, not before); and also you should create the results array within the permute function.
function permute(input){
function permutation(arr, position){
if(position >= arr.length) {
results.push(arr);
} else {
permutation(arr, position+1); // nothing is swapped, no need to copy anything
// you can also omit this line and start i=position
for (var i=position+1; i<arr.length; i++) {
var tmp = arr.slice();
tmp[position] = arr[i];
tmp[i] = arr[position];
permutation(tmp, position+1);
}
}
};
var results = [];
permutation(input, 0);
return results;
};
console.log(permute(['a','b','c'])); // [["a","b","c"],["a","c","b"],["b","a","c"],["b","c","a"],["c","b","a"],["c","a","b"]]

Fastest way to repeat an array in Javascript

I have been trying to figure out a fast way of creating an array based on repeating an element a given number of times. For my purposes, generally the element I'd be repeating is another array, and I'd be making a long repeated (2-dimensional) array out of it, so I'd prefer it to be fast. Note that in each example, c=[element] since that's how it naturally occurs in my code.
There are a few options here that I've found. At most basic is option 1:
function repeatSimple(c, n) {
var arr = [];
for (var i=0; i<n; i++) {
arr = arr.concat(c);
};
return arr;
};
Then from this question (Concatenate array to itself in order to duplicate it), gdbdmdb has another option:
function repeatApply(c, n) {
return [].concat.apply([], Array.apply(0, Array(n)).map(function() { return c }));
};
My thinking was (a) I don't really understand the second option well enough to know whether it's a good solution, and (b) it seems silly to have to call concat a whopping n times as in the first option. So I came up with one more:
function repeatBinary(c, n) {
var arr = [];
var r = 0;
while (n>0) {
r = n%2;
if (r>0) {
arr = arr.concat(c);
};
n = (n-r)/2;
if (n>0) {
c = c.concat(c);
};
};
return arr
};
This way, I only have to call concat at most 2log_2(n) times.
So, my question is, what is the fastest way to do this? Is it one of the options I'm looking at here or is there something else that blows them out of the water? Or will all of these options work at such similar speeds that it really doesn't make a difference?
I think the fastest way to do this witout even using the concat function :
function repeatSimple(element, times)
{
var result = [];
for(var i=0;i<times;i++)
result.push(element);
return result;
}
And if you don't want to use the push function , you can assign the value directly to the item on the array like this
function repeatSimple(element, times)
{
var result = Array(times);
for(var i=0;i<times;i++)
result[i] = element;
return result;
}
Another clever way to do this is to join an array and split it like this
function repeatSimple(element, times)
{
(result = Array(times).join("," + element).split(',')).shift()
return result;
}
But this last function returns an array of strings, you have to convert every element to the type you need, but anyway, these functions may help you

Only return values found in all arrays

Simple question, but i dont know how to solve it
I have several arrays, but i only want the values that all arrays have in common
Im using javascript.
Try looking for the value in each of the arrays using indexOF.
I never knew IE didn't support indexOf, but here's a quick fix from this post.
Something like this should work:
function getCommonElements() {
var common = [],
i, j;
if (arguments.length === 0)
return common;
outerLoop:
for (i = 0; i < arguments[0].length; i++) {
for (j = 1; j < arguments.length; j++)
if (-1 === arguments[j].indexOf(arguments[0][i]))
continue outerLoop;
common.push(arguments[0][i]);
}
return common;
}
Call it with any number of arrays as arguments:
var commonEls = getCommonElements(arr1, arr2, arr3, etc);
In case it's not obvious, the idea is to loop through the array from the first argument and test each of its elements against the other arrays. As soon as a particular element is found to not be in any of the other arrays from the other arguments continue on with the next element. Otherwise add the current element to the output array, common.
If you need to support browsers (IE < 9) that don't support the Array.indexOf() method you can either include the shim shown at the MDN page or replace the .indexOf() test from my code with another loop.
I think this should work.
var arr1 = [1,2,3,4]
, arr2 = [2,3,4,5]
, arr3 = [3,4,5,6]
, arrs = [arr1, arr2, arr3];
var all = arr1.concat(arr2.concat(arr3)).sort()
, red1 = all.filter(
function(val, i, arr) {
return i === arr.lastIndexOf(val)-1;
})
, red2 = red1.filter(
function(val, i, arr) {
var shared = true;
arrs.forEach(
function(arr, i, src) {
if (arr.indexOf(val) === -1)
shared = false;
})
return shared;
})
If you are only concerned with modern browsers that support reduce(), then use this solution:
Finding matches between multiple JavaScript Arrays
If you must support IE6, then use my solution below. Here's how I got this to work in IE6 using jQuery:
// Find common values across all arrays in 'a',
// where 'a' is an array of arrays [[arr1], [arr2], ...]
Object.common = function(a) {
var aCommon = [];
for (var i=0,imax=a[0].length,nMatch,sVal; i<imax; i++) {
nMatch = 0;
sVal = a[0][i];
for (var j=1,jmax=a.length; j<jmax; j++) {
nMatch += ($.inArray(sVal, a[j])>-1) ? 1 : 0;
}
if (nMatch===a.length-1) aCommon.push(sVal);
}
return aCommon;
}
Basically, you just loop through each value of the first array in 'a' to see if it exists in the other arrays. If it exists, you increment nMatch, and after scanning the other arrays you add the value to the aCommon array if nMatch equals the total number of the other arrays.
Using the sample data provided by Florian Salihovic, Object.common(arrs) would return [3, 4].
If you cannot use jQuery, then replace $.inArray() with the code provided by Mozilla:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/IndexOf

Javascript Garbage Collection on a Returned Array

I'm sure that this is an easy question for JS experts out there. Unfortunately for me I'm not one of them.
I've got the following situation. I'm creating an array in function b that I populate with some new objects. I then return that array back to function a (which called function b).
When I iterate through the returned array, the contents are all undefined. Off the cuff I figure that the JS garbage collector is probably involved here. How would I go about fixing this?
Sincerely,
mj
function a()
{
var x = b();
for( var v in x ){
//print out v.id and v.name
}
}
function b()
{
var y = new Array();
var m = new Object();
var n = new Object();
m.id = 1;
n.id = 2;
m.name = "alpha";
n.name = "bravo";
y.push( m );
y.push( n );
return y;
}
The problem is how you are "iterating" through your array. You are using the for-in statement, and this statement should be used to enumerate object properties, not to iterate over arrays or array-like objects.
From your code:
for( var v in x ){
//print out v.id and v.name
}
The for-in statement in every iteration will feed v with the name of each property, since you are using an array in your example, v will be '0', '1', etc.
You could access x[v] but I really encourage you to use a sequential for loop, for example:
for (var i = 0; i < x.length; i++) {
alert(x[i].id);
alert(x[i].name);
}
There are many reasons why to avoid for-in, when your purpose is "iterate" over numeric indexes on array like objects, see the following questions for more information:
Loop through array in JavaScript
JavaScript “For …in” with Arrays
You should not interate over an array in that way. You are looping through all of the properties/methods of the array, etc.
You can see this if you alert v http://jsfiddle.net/Xk7yB/
If you use a regular for loop, it works fine:
function a()
{
var x = b();
for(var i=0; i<x.length; i++){
alert(x[i].name);
}
}
http://jsfiddle.net/Xk7yB/1/
If you're using jQuery, you can also use:
$.each(x,function(){
alert(this.id);
alert(this.name);
});
The jQuery $.each() is most similar to the foreach mechanism you are used to.

Get first element of a sparse JavaScript array

I have an array of objects in javascript. I use jquery.
How do i get the first element in the array? I cant use the array index - as I assign each elements index when I am adding the objects to the array. So the indexes arent 0, 1, 2 etc.
Just need to get the first element of the array?
If you don't use sequentially numbered elements, you'll have to loop through until you hit the first one:
var firstIndex = 0;
while (firstIndex < myarray.length && myarray[firstIndex] === undefined) {
firstIndex++;
}
if (firstIndex < myarray.length) {
var firstElement = myarray[firstIndex];
} else {
// no elements.
}
or some equivalently silly construction. This gets you the first item's index, which you might or might not care about it.
If this is something you need to do often, you should keep a lookaside reference to the current first valid index, so this becomes an O(1) operation instead of O(n) every time. If you're frequently needing to iterate through a truly sparse array, consider another data structure, like keeping an object alongside it that back-maps ordinal results to indexes, or something that fits your data.
The filter method works with sparse arrays.
var first = array.filter(x => true)[0];
Have you considered:
function getFirstIndex(array){
var result;
if(array instanceof Array){
for(var i in array){
result = i;
break;
}
} else {
return null;
}
return result;
}
?
And as a way to get the last element in the array:
function getLastIndex(array){
var result;
if(array instanceof Array){
result = array.push("");
array.pop;
}
} else {
return null;
}
return result;
}
Neither of these uses jquery.
Object.keys(array)[0] returns the index (in String form) of the first element in the sparse array.
var array = [];
array[2] = true;
array[5] = undefined;
var keys = Object.keys(array); // => ["2", "5"]
var first = Number(keys[0]); // => 2
var last = Number(keys[keys.length - 1]); // => 5
I was also facing a similar problem and was surprised that no one has considered the following:
var testArray = [];
testArray [1245]= 31;
testArray[2045] = 45;
for(index in testArray){
console.log(index+','+testArray[index])
}
The above will produce
1245,31
2045,45
If needed you could exist after the first iteration if all that was required but generally we need to know where in the array to begin.
This is a proposal with ES5 method with Array#some.
The code gets the first nonsparse element and the index. The iteration stops immediately with returning true in the callback:
var a = [, , 22, 33],
value,
index;
a.some(function (v, i) {
value = v;
index = i;
return true;
});
console.log(index, value);
If you find yourself needing to do manipulation of arrays a lot, you might be interested in the Underscore library. It provides utility methods for manipulating arrays, for example compact:
var yourArray = [];
yourArray[10] = "foo";
var firstValue = _.compact(yourArray)[0];
However, it does sound like you are doing something strange when you are constructing your array. Perhaps Array.push would help you out?

Categories