how to remove following arguments after the array - javascript

destroyer(array1, some arguments) function should return the array1 excluding the arguments. I found some working ways like return arr = arr.filter(val => !rem.includes(val)); but I need to fix this code and find out why this code giving an incorrect result. It supposed to be [1]
function destroyer(arr, ...rem) {
for(let i = 0; i < arr.length; i++) {
if (rem.includes(arr[i])) {
arr.splice(i, 1);
};
};
return arr;
}
console.log(destroyer([3, 5, 1, 2, 2], 2, 3, 5));

function destroyer(arr, ...rem) {
const itemsToRemove = new Set(rem);
return arr.reduce((acc, curr) => itemsToRemove.has(curr) ? acc : [...acc, curr] ,[])
}
console.log(destroyer([3, 5, 1, 2, 2], 2, 3, 5));

The problem is the call of the function Array.prototype.splice within the for loop, this function is mutating the array and basically affects the indexes of the array, therefore the current index i is no longer valid.
To work around this, you can loop in a backward direction, this way we can mutate the array, and the current index is not affected.
One more thing, your approach is mutating the array, a better approach would be by using the function Array.prototype.filter along with the function Array.prototype.includes, see other answers.
function destroyer(arr, ...rem) {
for(let i = arr.length; i >= 0; i--) {
if (rem.includes(arr[i])) {
arr.splice(i, 1);
};
};
return arr;
}
console.log(destroyer([3, 5, 1, 2, 2], 2, 3, 5));

Or you can do it like this:
const destroyer=(arr, ...rem)=>arr.filter(v=>!rem.includes(v));
console.log(destroyer([3, 5, 1, 2, 2], 2, 3, 5));

Related

How can I ignore non-present values in a function without returning undefined?

I have this code:
const removeFromArray = function(...xNumber) {
return xNumber.reduce(function(xArray, yNumber) {
for (let i = 0; i < xArray.length; i++) {
if (xArray[i] === yNumber) {
const index = xArray.indexOf(yNumber);
xArray.splice(index, 1);
} else if (xArray[i] !== yNumber) {
continue;
}
return xArray;
}
});
};
console.log(removeFromArray([3, 4, 5, 1], 1, 3, 5, 10));
It's supposed to take in arguments that, if they match with the elements in the array, they get deleted and it returns the new array. If the argument is not related to the elements in the array, it ignores it. This function works well if I write only numbers that are related to the elements in the array. If I write a number, such as 10, that's not inside the array, it returns undefined.
In order to solve this, I need to play with conditionals I assume?
I'm sure my mistake is in the else if conditional, having continue in there is not good, I just didn't know what else to do.
You can do a much simpler implementation using .filter()
const removeFromArray = function(array, ...numbersToRemove) {
return array.filter(item => !numbersToRemove.includes(item))
};
console.log(removeFromArray([3, 4, 5, 1], 1, 3, 5, 10));
Without arrow functions after the request in the comments
const removeFromArray = function(array, ...numbersToRemove) {
return array.filter(function(item) {
return !numbersToRemove.includes(item);
});
}
console.log(removeFromArray([3, 4, 5, 1], 1, 3, 5, 10));

Why this rest parameter is usefull here?

I have two solutions for the same problem (both work), one is mine and the other one is from the internet.
In the internet's solution they add the variable modifiedArray. What is the point of doing that?
In the internet's solution, is the [...arr] in the modifiedArray variable not the same that the argument arr on the function removeFromArray()?
My solution:
const removeFromArray = function(arr, ...Args) {
for (i = 0; i <= Args.length; ++i) {
if (arr.includes(Args[i])) {
arr.splice(arr.indexOf(Args[i]), 1)
}
}
return arr;
}
module.exports = removeFromArray
Internet's solution:
const removeFromArray = function(arr, ...Args) {
let modifiedArray = [...arr]
for (i = 0; i < arr.length; ++i) {
if (modifiedArray.includes(Args[i])) {
modifiedArray.splice(modifiedArray.indexOf(Args[i]), 1)
}
}
return modifiedArray;
}
module.exports = removeFromArray
Test for both answers:
const removeFromArray = require('./removeFromArray')
describe('removeFromArray', function() {
it('removes a single value', function() {
expect(removeFromArray([1, 2, 3, 4], 3)).toEqual([1, 2, 4]);
});
it('removes multiple values', function() {
expect(removeFromArray([1, 2, 3, 4], 3, 2)).toEqual([1, 4]);
});
it('ignores non present values', function() {
expect(removeFromArray([1, 2, 3, 4], 7, "tacos")).toEqual([1, 2, 3, 4]);
});
it('ignores non present values, but still works', function() {
expect(removeFromArray([1, 2, 3, 4], 7, 2)).toEqual([1, 3, 4]);
});
it('can remove all values', function() {
expect(removeFromArray([1, 2, 3, 4], 1, 2, 3, 4, 5)).toEqual([]);
});
it('works with strings', function() {
expect(removeFromArray(["hey", 2, 3, "ho"], "hey", 3)).toEqual([2, "ho"]);
});
it('only removes same type', function() {
expect(removeFromArray([1, 2, 3], "1", 3)).toEqual([1, 2]);
});
});
The difference between your code and the other one, is that yours changes the arr parameter directly whereas the other first makes a copy of the array, and then modifies that copy.
When you pass an array to a function, you are actually passing a reference to that array, not a copy of it. This means that when you modify arr directly, you are also modifying the source array.
Here is a nice example:
const removeFromArray1 = function(arr, ...Args) {
for (i = 0; i <= Args.length; ++i) {
if (arr.includes(Args[i])) {
arr.splice(arr.indexOf(Args[i]), 1)
}
}
return arr;
}
const removeFromArray2 = function(arr, ...Args) {
let modifiedArray = [...arr]
for (i = 0; i < arr.length; ++i) {
if (modifiedArray.includes(Args[i])) {
modifiedArray.splice(modifiedArray.indexOf(Args[i]), 1)
}
}
return modifiedArray;
}
const arr1 = [1, 2, 3, 4];
console.log('Returned array 1', removeFromArray1(arr1, 3));
console.log('Source array 1', arr1);
const arr2 = [1, 2, 3, 4];
console.log('Returned array 2', removeFromArray2(arr2, 3));
console.log('Source array 2', arr2);
Here you can see that arr1 is modified after calling removeFromArray1, but arr2 is not modified after calling removeFromArray2. Changing the source array might have odd side-effects if you try to use the initial array expecting it not to be changed.
let modifiedArray = [...arr] is a simple way to make a shallow copy of the array.
The second solution is nearer to functional programming pattern (pure function).
In functional programming you dont push or delete items into existing arrays or objects.
You would rather create a new array with all the same items as the original array, Then you modify the duplicate and return it. The duplication is done by
let modifiedArray = [...arr]
The concept is described as pure Function. A function should not change anything outside the function. No side effects.

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

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]

Time complexity of a de-duping algorithm

Here is a function for removing duplicates from an array.
function dedupe(arr) {
var seen = {};
arr.forEach((e,i)=>{
if (seen[e]) {
arr.splice(i, 1);
}
seen[e] = true;
});
return arr;
}
console.log(dedupe([1, 2, 1, 3, 4]));
I am interested in the time complexity of this function.
If we assume that Array is backed by a real array, does that the time complexity can be analysed as follows?
allocation of seen: O(1)
enumerate all elements: O(n)
removal of a duplicate: O(n) (because re-allocation required item by item?)
return O(1)
So is this an O(n^2) algorithm?
Edit:
Corrected for indexing issue.
function dedupe(arr) {
var seen = {};
for(let i = 0; i < arr.length; i++) {
const e = arr[i];
if (seen[e]) {
arr.splice(i, 1);
i--; // we have modified the array and need to continue from the current index
}
seen[e] = true;
}
return arr;
}
console.log(dedupe([1, 2, 1, 3, 1, 4, 4, 7, 6, 7, 7, 7, 1, 5]));
For those upset by the performance of the above, this is O(N) I think.
I wanted to de-dupe in-place. Use of Set maintains the order across host environments.
function dedupe(arr) {
var seen = new Set();
for(let i = 0; i < arr.length; i++) {
seen.add(arr[i]);
}
arr.length = 0; // empty the array
return arr.concat(...seen.keys());
}
console.log(dedupe([1, 2, 1, 3, 1, 4, 4, 7, 6, 7, 7, 7, 1, 5]));
One approach would be to use the Javascript Set. You could simply do this:
const removeDuplicates = array => (new Set(array)).values()
This will return an iterator, and not an array, however this can easily be fixed. Also, sets are not yet supported in most browsers. The complexity of this should be O(n).
Another approach more similar to yours (but probably identical to the Set, since I'm gonna guess it's implemented using the same underlying structure) would be like this:
const removeDuplicates = array =>
Object.keys(array.reduce((agg, x) => { agg[x] = true; return agg }, {}))
The time complexity of this should be O(m+n) where m will be the number of unique items, which will always be <= n, therefore O(n).
Also, the time complexity you worked out seems correct.
You could save seen by filtering by index:
var t1 = [1, 2, 1, 1, 3, 1, 1, 4];
function uniqueList(list) {
return list.filter(function (value, index, arr) {
return list.indexOf(value) == index;
});
}
console.log(t1);
console.log(uniqueList(t1));
My answer, builds a new array. Maybe is O(n).
function dedupe(arr) {
var result = [];
var seen = {};
for(let i = 0; i < arr.length; i++) {
const e = arr[i];
if (seen[e]) {
//skip
} else {
seen[e] = true;
result.push(e);
}
}
return result;
}
console.log(dedupe([1, 2, 1, 3, 1, 4, 4, 7, 6, 7, 7, 7, 1, 5]));

Categories

Resources