Scope leak between arrays inside and outside of function scope? - javascript

I'm calling a function inside of my script main
function func(a) {
var idx;
a=a.sort();
for (idx = 0; idx < a.length + 1; idx += 1) {
if (a.indexOf(idx) === -1) {
return idx;
}
}
return 0;
}
var array = [2,1,0];
var b = func(array);
console.log(array);
The function argument (a) is an array that is being passed to the func function.
When I try to access the array in the main body of the program after calling this function it's sorted.
Does node.js link the scope between the array passed to the 'func' function and the array that was passed to it?
After calling this code, array is sorted. Why is that?
This is even true if I declare a new variable, b inside the function scope.
function func(a) {
var idx, b;
b = a;
b = b.sort();
for (idx = 0; idx < a.length + 1; idx += 1) {
if (a.indexOf(idx) === -1) {
return idx;
}
}
return 0;
}
var array = [2,1,0];
var b = func(array);
console.log(array);
The above code has the same issue.

It's not a scope leak but a twofold reason for what is happening:
because sort directly modifies the array it is applied on (while also returning it)
functions in JavaScript work with pass by reference for objects
For reason #1 look at this simple example:
var a = [3,4,1,2];
a; // [3, 4, 1, 2]
a.sort(); // [1, 2, 3, 4]
a; // [1, 2, 3, 4]
As you can see it returns the sorted array which is nothing more than the array itself that has been modified by the sort.
For reason #2 look at this simple example:
function foo(a) { a.push('hello'); }
var arr = [1,2,3,4];
arr; // [1, 2, 3, 4]
foo(arr); // undefined
arr; // [1, 2, 3, 4, "hello"]
So combining those two reasons you can see that you are passing a reference to the array into the function and then directly modifying it with a sort.
If you want to do the same thing without modifying the original array you could use Array.prototype.slice() which returns a shallow copy of the original array.
var a = [3,4,1,2];
var arr = a.slice();
a; // [3, 4, 1, 2]
arr; // [3, 4, 1, 2]
arr.sort(); // [1, 2, 3, 4]
arr; // [1, 2, 3, 4]
a; // [3, 4, 1, 2]

Related

Pass an array and further arguments into a function. How?

I have a function which takes an array and further arguments like this:
function arrayandmore([1, 2, 3], 2, 3)
I need to return the array ([1, 2, 3]) without those elements which equals the arguments coming behind the array. So in this case, the returned array would be:
([1]).
One of my approaches is:
function destroyer(arr) {
var args = Array.from(arguments);
var i = 0;
while (i < args.length) {
var result = args[0].filter(word => word !== args[i]);
i++;
}
console.log(result);
}
destroyer([1, 1, 3, 4], 1, 3);
Console returns:
[ 1, 1, 4 ]
I don't understand, why it returns one too - I don't understand, why it does not work.
It is the same with using splice.
function destroyer(arr) {
var args = Array.from(arguments);
var quant = args.length - 1;
for (var i = 1; i <= quant; i++) {
if (arr.indexOf(args[i]) !== -1) {
arr = arr.splice(arr.indexOf(args[i]));
}
console.log(arr);
}
}
destroyer([1, 1, 3, 4], 1, 3);
I think, both ways should work. But I don't figure out why they don't.
Your while won't work because result is being overwritten in every loop. So, it only ever removes the last parameter to the destroyer function
You can use the rest parameter syntax to separate the array and the items to be removed.
Then use filter and includes like this:
function destroyer(arr, ...toRemove) {
return arr.filter(a => !toRemove.includes(a))
}
console.log(destroyer([1, 1, 3, 4, 5], 1, 3))

Reverse the given array as argument in JavaScript

I am trying a JavaScript challenge. Not to use standard array reverse method but instead creating a new function to modify an array that given as argument and reverse its elements. Here is the example:
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]
However, I created this function but it didn't work:
function reverseArrayInPlace(arr) {
var newArr = [];
for (var i = arr.length - 1; i >= 0; i--) {
newArr.push(arr[i]);
}
arr = newArr; //This reverse arr successfully but won't work when called
return arr;
}
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [1, 2, 3, 4, 5], why? The arr variable above returned [5, 4, 3, 2, 1] but not here
This is the answer and it worked:
function reverseArrayInPlace(arr) {
for (var i = 0; i < Math.floor(arr.length / 2); i++) {
var old = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = old;
}
return arr;
}
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]
What is wrong with my method. What I don't get is the console.log did output the right reverse order but it will still show the original arrayValue when output. Can someone explain the difference to me?
The assignment is asking to modify the array in place, not to allocate new array/reassigning reference. This means you have to modify the variable passed as argument without allocating new memory for the variable returned (so you don't have another memory reference). The value you return from your function is not allocated to the original variable as it belongs to another scope and no assignment of returned value is performed (i.e. arrayValue = reverseArrayInPlace(arrayValue))
About in place algorythm, from wikipedia: In computer science, an in-place algorithm is an algorithm which transforms input using no auxiliary data structure. However a small amount of extra storage space is allowed for auxiliary variables. In-place algorithm updates input sequence only through replacement or swapping of elements. -> So you have to modify the original array passed, not to allocate a new one. As arr is inside function it is different from arr outside. The arr argument passed to function (which is a reference, not the whole thing) occupies different memory that arr outside
Your script works. If you try to display it something like this:
<p id="result"></p>
<script>
document.getElementById("result").innerHTML = reverseArrayInPlace(arrayValue);
</script>
it works
Here, see:
https://plnkr.co/edit/GJ57go?p=preview

How to compare multiple arrays and return an array with unique values in javascript?

I would like to compare multiple array and finally have an array that contain all unique values from different array. I tried to:
1,Use the filter method to compare the difference between 2 arrays
2,Call a for loop to input the arrays into the filter method
and the code is as follows
function diffArray(arr1, arr2) {
function filterfunction (arr1, arr2) {
return arr1.filter(function(item) {
return arr2.indexOf(item) === -1;
});
}
return filterfunction (arr1,arr2).concat(filterfunction(arr2,arr1));
}
function extractArray() {
var args = Array.prototype.slice.call(arguments);
for (var i =0; i < args.length; i++) {
diffArray(args[i],args[i+1]);
}
}
extractArray([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]);
However it does not work and return the error message "Cannot read property 'indexOf' of underfined" .... What's wrong with the logic and what should I change to make it works?
Many thanks for your help in advance!
Re: For all that mark this issue as duplicated ... what I am looking for, is a solution that can let me to put as many arrays as I want for input and reduce all the difference (e.g input 10000 arrays and return 1 array for unique value), but not only comparing 2 arrays .. The solutions that I have seen are always with 2 arrays only.
I don't use filters or anything of the sort but it will get the job done. I first create an empty array and concat the next array to it. Then I pass it to delete the duplicates and return the newly "filtered" array back for use.
function deleteDuplicates(a){
for(var i = a.length - 1; i >= 0; i--){
if(a.indexOf(a[i]) !== i){
a.splice(i, 1);
}
}
return a;
}
function extractArray() {
var args = Array.prototype.slice.call(arguments), arr = [];
for (var i = 0; i < args.length; i++) {
arr = deleteDuplicates(arr.concat(args[i]));
}
return arr;
}
var arr = extractArray([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]);
console.log(arr) //[3, 2, 5, 1, 7, 4, 6]

JavaScript - filter through an array with arguments using for loop

I am trying to use the filter method on an array to loop through the array based on a variable number of arguments.
Below is my attempt at this:
function destroyer(arr) {
var argArr = arr.slice.call(arguments, 1);
var filteredArray = arr.filter(function(val) {
for (var i = 0; i < argArr.length; i++) {
return val != argArr[i];
};
});
console.log(filteredArray);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
When I do this, only the first element of the arguments array is disposed of. This therefore returns:
[1, 3, 1, 3]
I have found a few examples online of possible ways to resolve this but they are vastly different from what I understand just yet. Is there any way to get mine to work, or even understand why the additional elements of the arguments array are not being called.
If you use ES6 you can do it with rest operator and Array#includes function
function destroyer(arr, ...params){
return arr.filter(item => !params.includes(item));
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
With your logic you can do like this. If val is equal to the current argArr's item then return false, if nothing was found after the loop: return true
function destroyer(arr) {
var argArr = Array.prototype.slice.call(arguments, 1);
var filteredArray = arr.filter(function(val) {
for (var i = 0; i < argArr.length; i++) {
if(val === argArr[i]){
return false;
}
};
return true;
});
console.log(filteredArray);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Because with your code you always test if current element in filter is equal or not equal to second parameter in function which is 2 and return true/false. Instead you can use indexOf to test if current element in filter is inside arguments array.
function destroyer(arr) {
var argArr = arr.slice.call(arguments, 1);
var filteredArray = arr.filter(function(val) {
return argArr.indexOf(val) == -1
});
console.log(filteredArray);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Problem is in your this line
return val != argArr[i];
Change logic like this , it will avoid to do extra looping also .
function destroyer(arr) {
var argArr = arr.slice.call(arguments, 1); debugger
var filteredArray = arr.filter(function(val) {
return !(argArr.indexOf(val) >= 0);
});
console.log(filteredArray);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);

Remove elements from array using javascript filter

I have two arrays and want to remove duplicates using filter function.
Here is my code:
arr1 = [1, 2, 3, 1, 2, 3];
arr2 = [2, 3];
result = [1, 1];
var result = arr1.filter(function(value, index) {
for (var i = 0; i <= arr2.length; i++) {
if (value !== arr2[i]) {
return value === arr2[i];
}
}
}
Thanks in advance! Any help would be great!
You can try to convert arguments into array and then check if the value from the initial array is in arguments array:
function destroyer(arr) {
// Converting arguments into array
var args = Array.prototype.slice.call(arguments);
arr = arr.filter(function (val) {
return args.includes(val)===false;
});
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3); // returns[1,1]
First of all, if its not a problem adding a library. I am using uniq from underscore.js.
uniq_.uniq(array, [isSorted], [iteratee]) Alias: unique
Produces a duplicate-free version of the array, using === to test object
equality. In particular only the first occurence of each value is
kept. If you know in advance that the array is sorted, passing true
for isSorted will run a much faster algorithm. If you want to compute
unique items based on a transformation, pass an iteratee function.
_.uniq([1, 2, 1, 4, 1, 3]);
=> [1, 2, 4, 3]
Other solution is using pure JS:
var newArray = [1, 2, 2, 3, 3, 4, 5, 6];
var unique = newArray.filter(function(itm, i, a) {
return i == newArray.indexOf(itm);
});
alert(unique);
But first you will need to combine your arrays in a new array:
var newArray = arr1.concat(arr2);
JS Fiddle
I hope this helped! :)
Here's one way without the filter function:
var arr1 = [1, 2, 3, 1, 2, 3];
var newArr = [];
for(var i = 0;i < arr1.length;i++){
if (newArr.indexOf(arr1[i]) === -1) {
newArr.push(arr1[i]);
}
}
Just use Array.prototype.filter()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
with Array.prototype.indexOf()
The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
var arr1 = [1, 2, 3, 1, 2, 3],
arr2 = [2, 3],
result = arr1.filter(function (a) {
return !~arr2.indexOf(a);
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
As in this JS Fiddle, using filter()
arr1 = [1, 2, 3, 1, 2, 3];
arr2 = [2, 3];
result = [1, 1];
var result = arr1.filter(myFunc);
function myFunc(value) {
for (var i = 0; i < arr2.length; ++i) {
// to remove every occurrence of the matched value
for (var j = arr1.length; j--;) {
if (arr1[j] === arr2[i]) {
// remove the element
arr1.splice(j, 1);
}
}
}
}
document.getElementById('result').innerHTML = arr1;
console.log(arr1);
// Output: [1,1]
<div id="result"></div>

Categories

Resources