I am trying to fill an array with ranges of values in a recursive function, but i see a weird thing happening while returning the array, though the array has values, when i alert it outside the function it gives me undefined. Not Sure whether its my code issue or any kind of behavior.
Same implementation when i tired using simple for loop it worked fine.
I don't know what title to give for this problem, please suggest me a good one.
JS Fiddle
With Recursion
var arr = [];
function fillArray(n,i){
if(arr.length !== n){
if(i===0)
arr[i] = i;
else
arr[i] = arr[i-1] + 1;
fillArray(n,++i);
}
else{
console.log(arr);
return arr;
}
}
console.log(fillArray(10,0));
With For Loop
var arr = [];
function fillArray(start,end){
for(var i=start,j=0;i<=end;i++,j++){
arr[j] = i;
}
return arr;
}
alert(fillArray(1,10));
function fillArray(n, i, a) {
a.push(i);
return a.length < n ? fillArray(n, ++i, a) : a;
}
console.log(fillArray(10, 0, []));
First, this is not a good example of something that should be implemented recursively in JavaScript. It's unidiomatic.
The reason the result is undefined outside the function is that your code fails to return the result of each successive recursive call. The recursion statement should look like:
return fillArray(n,++i);
Without that, the final call that does return the array will have its return value simply ignored by the penultimate call.
Take a look on your example:
var arr = [];
function fillArray(n,i){
if(arr.length !== n){
if(i===0)
arr[i] = i;
else
arr[i] = arr[i-1] + 1;
fillArray(n,++i); // ends without returning anything
}
else{
console.log(arr);
return arr; // return array
}
}
console.log(fillArray(10,0));
First of all I wouldn't declare value outside function and I wouldn't do with recursion (as you pollute your closure. But if you do so and you keep your function as it is, don't expect value as return here (as you edit variable outside of it).
var arr = [];
function fillArray(n,i){
if(arr.length !== n){
if(i===0)
arr[i] = i;
else
arr[i] = arr[i-1] + 1;
fillArray(n,++i);
} // return not needed
}
fillArray(10,0);
console.log(arr);
Related
I understand that there are ways to get unique elements in an array. This question isn't asking about that. This question is asking why indexOf returns -1 for "kale" in the unique_vegetables array once it's already been added. Is there something about indexOf that makes it not work in this situation?
var vegetables = ["kale", "broccoli", "kale"];
function produce(){
var unique_vegetables = [];
unique_vegetables = vegetables.map(function(v){
if (v.length > 0){ //irrelevant check to make sure the string has characters
var k = unique_vegetables.indexOf(v);
return k < 0 ? v : null;
}else {
return null;
}
})
return unique_vegetables;
}
var t = produce();
console.log(t, "unique vegetables") /// ["kale", "broccoli", "kale"]
https://jsfiddle.net/mjmitche/g6nn9nn6/
When you are using Array.map, there are 3 things that make it a whole.
Callback function
Return statement inside callback
Return from .map
Callback is the function that will be called on every iteration and will be passed 3 arguments viz., currentElement, index, and array itself.
Return from callback will initialize the value of this iteration in return array. This return array is a local array in .map and will not be accessible to you.
Return from map is the final step that returns the parsed local array pointed out in previous step.
Array.map would look something like this in simple implementation:
function myMap(arr, callback){
var temp = [];
for(var i = 0; i< arr.length; i++){
temp[i] = callback(arr[i], i, arr);
}
return temp;
}
var a = [1,2,3,4,5];
var b = myMap(a, function(n, i, a){ return n * 2 })
console.log(b)
Reference
Polyfill - MDN: You can refer it to check the actual code.
vegetables.forEach(function(v){
if (v.length > 0){
var k = unique_vegetables.indexOf(v);
if(k < 0) unique_vegetables.push(v);
}
})
unique_vegetables is an empty array until the map function finished and returned, so you need to change unique_vegetables while iterating.
Its a very small issue and for the life of me I can't figure out what it is. My brain has locked itself from thinking. I need someone else to have a look this code.
The output of the code should be: [1,0,0,0]
UPDATE:
The function should be able to read an array of numbers and if it finds any zeros within the array it should move them to the end of the array.
The output of the code keeps coming as: [0,1,0,0]
var arrNum = [0,0,0,1];
function test() {
for(var i=0; i<arrNum.length; i++){
if(arrNum[i] == 0){
arrNum.splice(i,1)
arrNum.splice(arrNum.length, 1, 0)
}
}
return alert(arrNum)
}
Here is a working plunker.
Apologies for this, I know the issue is something very small but my brain has stopped working now and I need a fresh pair of eyes.
With the way you have it written, you need to loop in the reverse order. You end up skipping indexes when you remove the index. Looping in the reverse direction keeps you from skipping them.
for(var i=arrNum.length-1; i>=0; i--){
You can use unshift() to insert at beginning of an array and push() to the end...
var arrNum = [0,0,0,1];
var output = [];
function test()
{
for(var i=0; i<arrNum.length; i++)
{
if(arrNum[i] == 0)
output.push(0);
else
output.unshift(arrNum[i]);
}
return alert(output)
}
var arrNum = [0,0,0,1];
var result = [];
arrNum.forEach(function(v) {
!!v ? result.unshift(v) : result.push(v);
});
console.log(result);
You are iterating with index i = 0,1,2,3 and at the same time removing first elements of array. So your iteration can not see the 1, it jumps over as it is moved to already iterated index. Easiest would be to just reverse the loop to bypass the issue.
var arrNum = [0,0,0,1];
function test() {
for(var i= arrNum.length; i >= 0; i--){
if(arrNum[i] == 0){
arrNum.splice(i,1)
arrNum.splice(arrNum.length, 1, 0)
}
}
return alert(arrNum)
}
Prefer built-in functions every time possible.
var output = [];
[0,0,0,1].forEach(function(num) {
if(num == 0) output.push(0);
else output.unshift(num)
})
Why don't you use a temporary array to help? The problem with your code is that the splice() function modifies the original array, and you are doing it inside the loop.
The code below produces what you need:
var arrNum = [0,0,0,1];
var arrResult = new Array();
function test() {
for(var i=arrNum.length-1; i>=0; i--)
{
arrResult.push(arrNum[i]);
}
arrNum = arrResult;
return alert(arrNum);
}
With another array to store the new values, you gain flexibility to do whatever you need with the data of the first array.
A nice little way using Objects - busy learning them so just posting a variation of deligation
var methods = {
moveZero: function(arr){
//console.log(arr);
var newArr = [];
for(var i = 0; i < arr.length; i++){
if(arr[i] === 0){
newArr.push(arr[i]);
}else{
newArr.unshift(arr[i]);
}
}
console.log(newArr);
}
}
var arrNum = Object.create(methods);
arrNum.moveZero([0,0,50,56,85,0,0,43,10,0,1]);
JSFiddle - https://jsfiddle.net/ToreanJoel/qh0xztgc/1/
The problem was you are modifying an array while looping over it in if statement.
Here is a working plunker of your example.
var len = arrNum.length;
var index = 0;
while(len) {
if(arrNum[index] == 0) {
arrNum.splice(index,1);
arrNum.push(0);
} else {
++index;
}
--len;
}
As the operation you want to do is actually sorting, for readability and compactness of code maybe you should be doing this instead:
var arrNum = [0,1,0,0];
arrNum.sort(function(a, b) {
return a == 0 ? 1 : 0;
});
It can contain any number and will keep order of others than 0
I am fairly new to JS and have a project to find the index of an array element, without using indexOf built in function. I have tried to search for solutions, but all I get are examples of the aforementioned built in function, which I already know how to use. Can anyone provide a simple example for me to go on?
My mind goes towards something like this, but please note I am new to this and it is an academic exercise that I really want to understand:
var index;
var target = 10;
for(var val in collection){
if(collection[val] === target){
index = val;
}
return index;
}
This attempt is almost correct. You seem to already understand of what is required: loop over the elements of the array until you find a match, and then return the index of that match.
You've made a few mistakes, though. Let's walk through some improvements, step by step.
Your return statement is inside the loop, but outside of the if. You only want to return if you're found a match. Currently, you always return after the first iteration of the loop!
function myIndexOf(collection, target) {
var index;
for(var val in collection){
if(collection[val] === target){
index = val;
return index;
}
}
}
There is no need for a separate index variable. You can return val as soon as you determine it's the correct answer.
function myIndexOf(collection, target) {
for(var val in collection){
if(collection[val] === target){
return val;
}
}
}
You should loop using a numeric for loop, not a for-in loop. for-in loops are not guaranteed to have a set order, so you may not always get the lowest index that is a match. (Also, for-in could match on non-numeric property names, which might not be what you want.)
function myIndexOf(collection, target) {
for(var val=0; val<collection.length; val++){
if(collection[val] === target){
return val;
}
}
}
To act just like indexOf, you could return -1 in the case that you don't find a match.
function myIndexOf(collection, target) {
for(var val=0; val<collection.length; val++){
if(collection[val] === target){
return val;
}
}
return -1;
}
Note: for..in should not be used to iterate over an Array where the
index order is important.
for..in - JavaScript | MDN
var find_index = function(collection, item) {
for (var i = 0; i < collection.length; ++i) {
if (collection[i] === item) {
return i;
}
}
};
find_index([5,4,3,2,1], 5)
When looping through an array you should use a simple for loop from index 0 to Length-1 of your array. Don't use for...in because it can iterate properties of the array that aren't the actual contents of the cells and the order is not guaranteed. You want to find the first match to have the same behavior as .indexOf. So the correct implementation would look something like this:
function myIndexOf(array, target) {
for (var i=0; i < array.length; i++) {
if (array[i] === target) {
return i;
}
}
// item was not found
return -1;
}
You can use in statement to iterate an array, assumings keys are values. Here val will be 0, 1, 2... so you can return it.
Then, you can use the return inside the if : it will stop the function and return the value just right you find what you are loonking for.
The === is the strict comparaison operator, checking var type, allowing you to test this is the exact value you are looking for.
You can add a return with an other value (here -1) if the value is not found at the end of the loop.
function myIndexOf(array, search) {
for(var val in array){
if(array[val] === search){
return val;
}
}
return -1;
}
var myArray = ['a', 'b', 'c'];
console.log(myIndexOf(myArray, 'c')); //2
console.log(myIndexOf(myArray, 'f')); //-1 <- Not found
This would work:
var index = 0;
var target = 'c';
var collection = ['a', 'b', 'c', 'd'];
function findIndex(){
for(var val in collection) {
if(collection[val] === target){
return index;
}
index++;
}
}
findIndex();
You can use every as well. Iterate through the array, return true if value doesn't match value being searched so every continues, otherwise set ind and return false.
var getIndex = function(arr, match){
var ind = -1;
arr.every(function(val, index) {
if (val === match){
ind = index;
return false;
}
return true;
});
return ind;
}
getIndex([1, 2, 3], 2);
So we are practicing functional javascript in my programming class with this assignment and I just can't get it to work right. Any advice in making this code work would be appreciated. Everything but the body was given for me to use. Here is what I have come up with:
(It is always sending me just the first array index content rather than all of them reversed. I tried changing it to
if(arr.length <= 1) return arr;
but that never hits the base case.)
function ReverseArray(arr) {
//base case
if(arr.length == 1)
{
return arr[0];
}
if(arr.length == 0)
{
return 0;
}
var head = arr.pop;
var newArr = [head, ReverseArray(arr)];
return newArr;
}
x = y <--assignment
z == y <-- comparison
Looking at your code:
if(arr.length = 1)
needs to be
if(arr.length == 1)
same with the zero check
AND you are not calling pop
var head = arr.pop;
you need to parenthesis
var head = arr.pop();
This is the most precise and clean way to do it in a single line with the ternary operator.
function reverse(arr) {
return arr.length < 2 ? arr : [arr.pop()].concat(reverse(arr));
}
console.log(reverse([4, 3, 3, 1]));
Here's a runnable example with a working function. FYI there is also a built-in function that will do this for you.
I think other than the confusion with assignment/comparison operators, when you were building the result array, you should be using Array.concat() to concatenate your array, instead you were building a new array where the second item was an array itself.
var a = [1,2,3,4,5];
console.log(ReverseArray(a));
function ReverseArray(arr) {
if(arr.length < 2) {
return arr;
} else {
return [arr.pop()].concat(ReverseArray(arr));
}
}
I need to check if array number 2 contains all of the values in array number 1. I am not aware of any method that does this so I developed one that works, I think. Is there a better way to do this, is this a good solution?
var contains = function(a1, a2){
var cCount = 0;
for (var i=0; i<a1.length; i++){
for (var j=0; j<a2.length; j++){
if (a1[i] == a2[j]){
cCount++;
}}}
if (cCount == a1.length){
return true;
}
};
You could check sizes before starting. return false when one is not present instead using a counter. and return true if it reach the end. And use indexof instead looping through a2 every time.
var contains = function(a1, a2){
if (a1.length>a2.length) return false;
for (var i=0; i<a1.length; i++){
if (a2.indexOf(a1[i])<0) return false;
}
return true;
}
just a bit simplified code:
function contains(array1, array2){
var found = false;
for (i in array1) {
for (j in array2) {
if (array1[i] == array2[j]) {
found = true;
}
}
if (!found) return false;
}
return true;
}
another solution I don't really like it but it's shorter...
function contains (arr1, arr2) {
var specialChar = "|"; // Use any char or a sequence that won't exist in values.
var str = specialChar + arr2.join(specialChar) + specialChar;
for (i in arr1) if (str.indexOf(specialChar + arr1[i] + specialChar) == -1) return false;
return true;
}
Your solution is O(n * n) i.e. order n-squared.
You could sort the arrays first and then sequentially check the elements in the sorted arrays for a match. This will give you an O(n log n) solution. Also you can short circuit the check by ensuring that the size of array2 <= the size of array1.
Evidently this only matters if your arrays are sufficiently big.
You can do this in O(n) if you have a 3rd object that you use to keep track of the items that have been seen already. This assumes that the lookup in seen is O(1) (which presumably it is - What's the big O for JavaScript's array when used as a hash?)
var seen = {};
arr2.forEach(function(el) {
seen[el] = true;
});
var allContained = true;
arr1.forEach(function(el) {
if ( allContained && !seen[el] ) {
allContained = false;
}
});
return allContained;
I'd personally use the Array.every() method (though this is, of course, dependent upon a browser that implements this method) in conjunction with Array.indexOf(), which would result in something akin to the following:
var contains = function(needle, haystack){
return needle.every(function(a){
return haystack.indexOf(a) > -1;
});
};
Combining that with the approach you've already produced (testing for browser-support):
var contains = function(needle, haystack){
if ([].every){
return needle.every(function(a){
return haystack.indexOf(a) > -1;
});
}
else {
var result = true;
for (var i = 0, len = needle.length; i < len; i++){
if (haystack.indexOf(needle[i]) === -1) {
return false;
}
}
return result;
}
}
var a1 = [1,2,3],
a2 = [1,2,3,4];
console.log(contains(a1, a2));
JS Fiddle demo.
Note that the else code isn't optimised, it's simply there to demonstrate the code. Having said that, there is a shim for Array.every() at the MDN page (in the references, below) that might make things easier.
References:
Array.prototype.every().
Array.prototype.indexOf().