Why is the variable i in the splice function decremented? - javascript

function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] === elem) {
arr.splice(i--, 1);
newArr = arr;
break;
}
}
}
return newArr;
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
I have defined a function, filteredArray, which takes arr, a nested array, and elem as arguments, and returns a new array. elem represents an element that may or may not be present on one or more of the arrays nested within arr. Modify the function, using a for loop, to return a filtered version of the passed array such that any array nested within arr containing elem has been removed.
The expected output is [] (an empty array).
Question: Why is the variable i in the splice function decremented?

Because splice updates the original array in place. And in the for loop the condition to check if i < arr.length is calculated on every iteration.
Lets say you have an array of 10 items. In the first iteration arr.length will be 10. After that if you splice and remove 1 item from the array and then try to console.log(arr.length) you will see the length is updated to 9.
If you want to remove all the item in the sub array that is equal to the elem you can do that,
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] === elem) {
arr[i].splice(j, 1);
}
}
newArr.push([...arr[i]])
}
return newArr;
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));

Related

How to get the index of a multidimensional array and splice that array

There is a problem in FreeCodeCamp.I'm not here to search solution to that problem. While trying to solve the problem I found some lines of my code do not work. I can not understand why that is not working. So I am here to ask YOU, good people, to help me.
problem
There is a function. I will pass an array and a number to that function. And what I need to return is also an array.
The array is a multidimensional array.
what I want to do
First of all I want to check if the inner or subarray contains the number i passed while calling the function. If that contains i need the index of that number in that subarray. Then I want to delete the number from that subarray using splice(). At last I wanted to return an array where there are sub arrays in it but none of them contain the given number.
where i am stuck in
But I am stuck in finding the index of the number in sub arrays, how can i use splice() to delete the number? Is it possible to do this way? Do you have any better suggestion for me?
my code
where for the first for loop it just prints -1
for the second loop, it prints the index of the array,not the index of the subarray.
function filteredArray(arr, elem) {
let newArr = [];
// Only change code below this line
newArr = [...arr]
let L = arr.length;
for (let i = 0; i < L; i++) {
// -------1-----------
for (elem in newArr[i]) {
console.log(newArr[i].indexOf(elem));
}
}
console.log('first loop ends')
for (let i = 0; i < L; i++) {
// --------2---------
for (let j = 0; j < newArr[i].length; j++) {
if (newArr[i][j] == elem) {
console.log(newArr[i].indexOf(elem))
}
}
// Only change code above this line
return newArr;
}
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
function filteredArray(arr, elem) {
let newArr = [];
// Only change code below this line
newArr = [...arr]
let L = arr.length;
// for (let i = 0; i < L; i++) {
// // -------1-----------
// for (elem in newArr[i]) {
// console.log(newArr[i].indexOf(elem));
// }
// }
console.log('first loop ends')
for (let i = 0; i < L; i++) {
// --------2---------
for (let j = 0; j < newArr[i].length; j++) {
if (newArr[i][j] == elem) {
console.log(newArr[i].indexOf(elem))
}
}
// Only change code above this line
return newArr;
}
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
When removing values from an array you don't want to use a mutating method like .splice() -- the original array will change. If .splice() removes a number, the length of the array decreases and all indexes at and after the index of the removed number will shift (unless you replace that number instead). The non-mutating methods such as filter() and .map() makes a copy of the array and returns the copy leaving the original array intact. See this article for a easy reference of what mutates and what doesn't.
You could simplify the process of removing a given number from an array of arrays by using .map() on each sub-array and .filter() each sub-array with the condition of returning only numbers that do not equal the given number.
const data = [[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]];
const filterCols = (target, arrArr) =>
arrArr.map(sub => sub.filter(num => num !== target));
console.log(filterCols(3, data));

Looping into nested arrays

I am going through an exercise that asks me to remove the arrays that have elements that match with another variable.
e.g.
filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18)
should return [[10, 8, 3], [14, 6, 23]]
Given the fact that we are working with nested arrays I though about using a double for to loop into each element.
Like this:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] != elem) {
newArr.push(arr[i]);
}
}
// change code above this line
return newArr;
}
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
The expected result was to have an empty array, but it gives me:
[3, 2, 3]
The right solution is as follow:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i].indexOf(elem) == -1) { //Checks every parameter for the element and if is NOT there continues the code
newArr.push(arr[i]); //Inserts the element of the array in the new filtered array
};
};
return newArr;
};
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
Which makes sense, but I do not understand why mine is wrong.
Your issue is with:
if (arr[i][j] != elem) {
newArr.push(arr[i]);
}
You're pushing your array into newArr each time an inner element (newArr[i][j]) doesn't equal the filter element (elem). Instead, you want to push it into newArr if all the items in arr[i] are not equal to the elem. You could do this a few ways, one way would be to use a variable found which acts as a flag indicating whether the elem was found in any of the inner lists, and then add it if it was not found:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
let found = false;
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] == elem) {
found = true;
}
}
if(!found) {
newArr.push(arr[i]);
}
}
// move return out of for loop
return newArr; // change code above this line
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26],
[19, 3, 9]], 3));
You are getting [3, 2, 3] because you are returning from inside the first for loop. So, it only ever checks the first inner array. Even if you move it outside, the entire 2d array will be returned because every inner array has an element which will fail arr[i][j] == elem condition.
Alternatively, you could use filter and includes like this:
function filteredArray(arr, elem) {
return arr.filter(a => !a.includes(elem))
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
You check every element of the subarray, and if that does not match elem you push the subarray to the result. That means for [3, 18, 6] in your first example, it will check 3 against elem (18), then push that array, check 18 against elem, which won't fullfill the condition, then it will check 6 against 18 which does match again, the array gets pushed again. Instead you should check the whole array against the value, then push.
outer: for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] == elem) {
continue outer; // if one matches, exit the inner loop
}
// all checked, push
newArr.push(arr[i]);
}
}
There some wrong things in your code:
You let return in for loop.
You check every element in every sub array and push to result array when having the difference
I edit your code as below:
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) { var check = false;
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] == elem) {
check = true;
}
}
} // change code above this line
return newArr;
}

Elements in Array1 that are equal to or less than elements in array2?

Scenario:
If given an Array1, such as [1, 2, 3], and Array2 [2,4], I need the output to be [2, 3] because there are 2 elements in Array1 that are less than or equal to Array2[1] and 3 elements in Array1 that are less than or equal to Array2[2].
So far, I've got this...
function counts(nums, maxes) {
let empArr = [];
//compare SECOND ARRAY maxes
for (let i = 0, count = 0; i < maxes.length; i++) {
//to FIRST ARRAY nums
for (let j = 0; j < nums.length; j++) {
if (nums[j] <= maxes[i]) {
count++;
}
}
empArr.push(count);
}
return empArr
}
console.log(counts([1, 2, 3], [2, 3]));
This gives me [2, 5] yet I expect [2, 3]. Any help here? Thanks!
The count = 0; declaration within your for() doesn't do what you seem to think it does. Declarations of this nature within a for constructor are only run once before the first iteration of the loop. Manually reset your count at the top of the loop:
function counts(nums, maxes) {
let empArr = [];
//compare SECOND ARRAY maxes
for (let i = 0; i < maxes.length; i++) {
let count = 0;
//to FIRST ARRAY nums
for (let j = 0; j < nums.length; j++) {
if (nums[j] <= maxes[i]) {
count++;
}
}
empArr.push(count);
}
return empArr
}
console.log(counts([1, 2, 3], [2, 3]));

Why should we decrement an i variable and use break in a function?

What is the purpose of decrementing the "i" variable and using "break" in this function?
function filteredArray(arr, elem){
let newArr = [...arr];
for(let i = 0; i < newArr.length; i++){
for(let j = 0; j < newArr[i].length; j++){
if(newArr[i][j] === elem){
newArr.splice(i, 1);
i--;
break;
}
}
}
return newArr;
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
This is because by using newArr.splice(i, 1); you are removing the current index item from the array, so since all indexes will be moved by -1 for all elements following i at each splice, you then have to reduce i by 1, so you dont skip elements

Multidimensional array returns several undefined values upon iterating in javascript

I have a multidimensional array that returns undefined after the last value of every sub-array. Here is my code:
var bigArray = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
];
for (i = 0; i < bigArray.length; i++) {
for (j = 0; j <= bigArray[i].length; j++) {
console.log(bigArray[i][j]);
}
}
Remove the = part from the condition of the second loop. You tries to access an element out of the range of the array. Also declare your variables with var, let or const - in the case with i and j.
var bigArray = [
[1,2,3],
[4,5,6],
[7,8,9],
[10,11,12]
];
for(var i = 0; i < bigArray.length; i++) {
for(var j = 0; j < bigArray[i].length; j++) {
console.log(bigArray[i][j]);
}
}
In this case, '.length' method will return the total number elements in that array, But array index starts from 0. So if an array contains n elements the array index of the last element will be n-1. And if you are trying to access an array with index n it will return an ArrayIndexOutOfBound Exception.
You can try this code
var bigArray = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
];
for (i = 0; i <= bigArray.length-1; i++) {
for (j = 0; j <= bigArray[i].length-1; j++) {
console.log(bigArray[i][j]);
}
}

Categories