can indexOf work on an updating array? - javascript

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.

Related

How to compare the each value present in array by using .filter

This is my code to filter out the record
for (var k = 0; k < $scope.hockeyPlayersId.length; k++) {
var val = $scope.hockeyPlayersId[k];
$scope.filterhockeyPlayers = $scope.Players.filter(function (obj, index) {
var returnVal = true;
if (val) {
if (obj.PlayersId == val)
return 1
else
return 0;
}
return returnVal;
});//End of filter function ;
}
val contains all the Ids of the player which play hockey. I am comparing the each PlayersId of obj with val but $scope.filterhockeyPlayers returns wrong value if $scope.hockeyPlayersId = ['22','12','21'] then returns the players which contains only 21 id. I want player of 22 and 12 also. $scope.filterhockeyPlayers value is lost after each for loop.
There are a few things wrong with your code:
You're overriding $scope.filterhockeyPlayers at each iteration of the for loop, so only the results of the last item of $scope.hockeyPlayersId will be used, the rest are omitted.
returnVal is totally useless. Either 1 or 0 will be returned due to if-else.
Now, to fix this you'll have to change the code so that filter is the outermost. And for each object in $scope.Players just check if the id of that object is included in $scope.hockeyPlayersId by using Array#indexOf or Array#includes:
$scope.filterhockeyPlayers = $scope.Players.filter(function (obj) { // filter objects from $scope.Players
return $scope.hockeyPlayersId.includes(obj.PlayersId); // where the id is included in $scope.hockeyPlayersId
});
Which is the same as using a for loop like so:
$scope.filterhockeyPlayers = $scope.Players.filter(function (obj) {
for (var k = 0; k < $scope.hockeyPlayersId.length; k++) {
if(obj.PlayersId == $scope.hockeyPlayersId[k]) {
return true;
}
}
return false;
});
I hope it makes sense ;-)

How to fetch/ get all the arguments of the function?

With JavaScript we have arguments property that lets us get the arguments of the function. I generally do it this way
function sum(){
var agumentCount = arguments.length;
var count =0;
var sumArguments = [];
// Fetching the arguments
while(count != agumentCount){
sumArguments.push(arguments[count]);
count++;
}
// function logic -- neglect this
var data = 0;
for(var i=0; i<sumArguments.length;i++){
data+=sumArguments[i];
}
return data;
}
// Calling the function
sum(2,3);
sum(9,15,65,458748);
sum();
sum(1);
Is there better way of fetching the arguments, as this takes O(n), where n is the number of arguments for the function.
You can use this code it will not reduce complexity but it's much better approach to this kind of operation -
function sum() {
var arr = Array.from(arguments);
return arr.reduce(function(total, x) {
return total + x;
}, 0)
}
console.log(sum(1, 2, 3, 4, 5)); // 15
You could use ..., the spread operator to work with variable number of arguments:
function sum(...nums){ //The arguments are stored in the nums array.
var sum = 0;
nums.forEach(function(num){
sum+=num;
});
return sum;
}
sum(1,2,3,4,5,6); //21
Check this out for more information.
EDIT:
Use the reduce function for more concise and readable code:
function sum(...nums){
return nums.reduce(function(add,num){
return add+num;
});
}
sum(1,2,3,4,5,6); //21
You do not need to fetch the arguments.
You can check if the first argument is an array and loop through that array.
function sum() {
let array= [],
ans = 0;
// Array check.
if (arguments[0] instanceof Array)
array = arguments[0];
else array = arguments;
// Sum all from array
const max = array.length;
for (let i = 0; i < max; i++) {
ans += array[i];
}
return ans;
}
console.log(sum(1,2,3));
console.log(sum([4,5,6]));
console.log(sum());
console.log(sum(7,8));
arguments is like array because
1.it return item by index;
2.it has length property.
but actually it is not an array because it is not generated by constructor Array, therefor it doesn't inheritance the prototype functions of Array.
This is a defect for the design of JavaScript.
Lucky you can still "borrow" the prototype functions of Array to generate an actual array.
function a(){
var arr=Array.prototype.concat.apply(arguments);
}

Array filter function

Can anyone please help me out with this code? Apparently, I just figured out that one can't run a for loop within a filter function. How can I check all the items in array "a" in the filter function?
function destroyer(arr) {
// Remove all the values
var a = [];
for (var i = 1;i < arguments.length;i++){
a.push(arguments[i]);
}
return arr.filter(function(x){
for (var b = 0;b <a.length;b++) { if (x !== a[b]){return x;} }
});
}
Array filter methods take a callback function definition which is returns true or false. true will include the item in the resulting array. false will exclude it.
Here is an example of how to use .filter():
var arr = [1,2,3,4,'a','b','c','d'];
var filteredArr = arr.filter(function(item, index) {
return typeof item === 'string' && index < 6;
});
console.log(filteredArr);
You can refer to variables outside the scope of the filter function as well:
var arr1 = [2,4,6,8];
var arr2 = [5,6,7,8];
var filteredArr = arr1.filter(function(item) {
return arr2.indexOf(item) > -1;
});
console.log(filteredArr);

Find the index of an array element without using built in indexOf function

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);

Recursive function in Javascript to fill Array?

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);

Categories

Resources