I'm doing "experiments" on a little example to understand the use of filter() and map() in JavaScript, and I have a question, based on the following code.
var numbers = [1, 4, 9, 25, 36, 49];
var roots = numbers.filter(function() {
for (i = 0; i < numbers.length; i++) {
if (numbers[i] > 10) {
var index = numbers.indexOf(numbers[i]);
numbers.splice(index, 1);
}
}
return numbers;
}).map(Math.sqrt);
console.log(numbers);
// -> [1, 4, 9]
console.log(roots);
// -> [1, 2, 3]
Why when I put numbers[i] > 10 as a condition the output is correct, whereas if I put numbers[i] < 10 the outcome is the following
console.log(numbers);
// -> [25, 36, 49]
console.log(roots);
// -> [1, 5, 7]
Where the numbers array is correct, but the roots array is messed up?
Your filter function is mutating the numbers array on which its operating; it should just return true or false depending on whether you want the item in the filtered results or not. For example
var roots = numbers.filter(function(n) {
return n > 10;
}).map(Math.sqrt);
In this case numbers is never changed, but roots contains all elements in numbers that are greater than 10.
example fiddle
You are using filter but inside the callback, you are doing your own filter ... which I doubt is intentional. If you break down what your code is doing conversationally, it is basically "for each element in the array, iterate through the entire array (for loop) and in that loop iterate through the entire array again (indexOf)...". At this point you can probably determine something is wrong. Also Array.splice mutates the original array which is usually undesirable.
Here is an example of how you might want to use filter and map
var numbers = [1, 4, 9, 25, 36, 49];
// get numbers greater than 10
numbers.filter(n => n > 10)
// => [25, 36, 49]
// get numbers greater than 10 and take the square root of each number
numbers.filter(n => n > 10).map(Math.sqrt)
// => [5, 6, 7]
Note that these methods are chainable but never mutate the original array. This gives you a great amount of flexibility for performing array computations.
This code is not doing what you think it's doing. It'll be acting very strangely because you're mutating the numbers array as you go along in the for loop.
The correct use of filter is to return true/false for each value, not return a new array. Return true to keep an element, false to remove it.
This is what you're after:
var numbers = [1, 4, 9, 25, 36, 49];
// notice "number" is taken as an argument
var roots = numbers.filter(function(number) {
// return true to include this number, false to reject it
return number < 10;
}).map(Math.sqrt);
console.log(numbers);
// NOTE: has not been changed
// -> [1, 4, 9, 25, 36, 49]
console.log(roots);
// -> [1, 2, 3]
To get an understanding of where your results are coming from, let's walk through each iteration of your code:
filter will run for each element of the array. the for loop will then go through and modify the array.
for number > 10
filter: value of 1
for the first 3 iterations of the for loop, nothing happens, then:
i = 3, so numbers[3] = 25. this passes the condition in your for loop, causing the splice, which will change numbers to [1, 4, 9, 36, 49]
this is where it gets weird #1
In the next iteration of the for loop, i will be 4, but the array has been changed. You may expect the value of 36 to be checked next, but because the array has been modified, and 36 is now in the place of 25, it will be missed. The next value to be checked is in fact 49. Similar reasoning shows that 49 will also be removed.
When the for loop is complete, you are left with numbers = [1, 4, 9, 36]
You then return numbers, which is truthy, which filter interprets as an instruction to keep 1 in the array.
filter: values 4, and 9
The same reasoning can be followed to show that the values of 4 and 9 will remain in the numbers array, and 36 will be removed.
Now, because 25, 36, and 49 have been removed from the array, filter has completed its job, leaving [1, 4, 9] to be passed to map giving [1, 2, 3].
Result
It's actually provided the inverse of the correct answer.
for number < 10
This is where it get really weird.
filter: value of 1
the for loop will remove 1, skip 4 (since it now takes the place of 1), remove 9 (which is in place of 4), skip 25, and keep the rest. This returns a value of [4, 25, 36, 49], which is truthy, and intepreted as keeping 1.
result of filter so far is [1].
filter: value of 25 (since it's now in the 2nd position in the array as 1 was removed)
the for loop will remove the 4, skip 25, and keep the rest. This returns a value of [25, 36, 49], which is truthy, so interpreted as keeping 25.
result of the filter so far is now [1, 25]
filter: value of 49 (since it's now in the 3rd position in the array as 1, 4, and 9 have been removed)
the for loop will keep all of the values since they're all greater than 10, meaning that the return value will be [25, 36, 49], which is truthy, which means that 49 is kept.
result of the filter will be [1, 25, 49], mapped with Math.sqrt is [1, 5, 7]
Result
0_o
Conclusion
Never, ever modify an array as you're looping or using array functions on it.
Related
const data = response.data
console.log(data)
const temp = data.ssps_with_scated.splice(5, 1)(1, 3)[0]
data.ps_with_ed.splice(2, 1, 0, temp)
i am trying to achieve finally i got it. But issue is, i cant expect the array value same all the time. So i have decided to re-arrange the array values based on the ID.
Well,
splice(7,1)(21,3)
This code will cause an error. Since Array.prototpy.slice returns a new array.
It would be the same if you would do this:
const a = [1,2,3]
const b = a.splice(1,1);
b(2,1) // b.splice(...) is not a function
EDITED:
Maybe there is a faster/better solution but...
You can make it more general but for your case only:
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
const first = array[7];
const second = array[21];
// Add elements on certain indices in array (second and third)
array.splice(2, 0, first, second)
// Remove first from the array (index is 7 + 2 because we added 2 elements)
array.splice(9, 1)
// Remove 21 from the array (index is 22 - 1 because we added 2 elements and removed 1, not: number 21 is on index 22)
array.splice(21, 1);
data shouldn't be a const since the value is getting updated. Splice can also only be called on one array at a time. If you need to call it on multiple arrays, create a loop or iterate over them.
If you want to inject the current value of the 7th position into the 2nd position... you'd need to do something like...
array.splice(2, 0, array[7])
I have an array of rows from a Google Spreadsheet interspersed with numbers between the bounds of 1 and 800:
var rowPositions = [1,3,4,5,9,10,11,12...795,799,800]
And, for efficiency's sake, I need to make an API call to the function deleteRows, which accepts two parameters:
deleteRows(positionOfFirstRow, howManyRowsShouldBeDeletedStartingFromFirstRow)
Google Documentation for deleteRows.
How can I create a function in Javascript that calls deleteRows a minimal number of times for a given array? IE, using the aforementioned array as an example, the function calls deleteRows to remove the row at position 1, then calls it again to delete 3,4,5, then again to delete 10,11,12, etc...?
In other words, how can I transform that rowPositions array into a two-dimensional one, ex.:
var 2DrowPositions = [[1,1],[3,2],[5,1],[9,4]]
which I can then use to call the deleteRows function once per provided coordinate.
If you are given an array of items to delete like [1, 3, 4, 5, 7, 8, 9, 15, 18, 19, 20, 23] you can step through that array and look for consecutive numbers. Keep track of how many consecutive numbers you see and when you hit a non-consecutive number, save the old one and start again.
Here's one way to do that, which is reasonably easy to read:
let del = [1, 3, 4, 5, 7, 8, 9, 15, 18, 19, 20, 23]
let res = []
let curr = {start: del[0], count: 0}
del.forEach((item, i, arr) => {
if (i === 0 || arr[i] === 1 + arr[i-1]) curr.count++
else {
res.push(curr)
curr = {start: arr[i], count:1}
}
})
res.push(curr)
console.log(res)
This will return an array of objects of the form {start, count} which you can use in your function with something like:
res.forEach(r => deleteRows(r.start, r.count))
Find the correct passcode in the array and we'll do the rest. We can't disclose more information on this one, sorry.
Each entry in the first array represents a passcode
- Find the passcode that has no odd digits.
- For each passcode, show us the amount of even digits.
- If it has no odd digits, show us that you've found it and increase the number of terminals by one.
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3],
];
so, i've tried almost everything i could think of. modulo, function, for loop and i can't seem to get it. i'm a beginner and this is an important exercise i have to do. but what do i do? it asks for the amount of even digits in each passcode, so i have to get the array within the array and then code something that i don't know to find even values. i'm stuck
Your question is not really suitable for StackOverflow, you should at least try to write something and see how far you get.
Anyhow, you seem to want to iterate over the elements in passcodes to find the array with no odd numbers.
The first task is to how to determine if a number is even. That is as simple as looking for the remainder from modulus 2. If the remainder is zero, then the number is even, otherwise it's odd.
So a simple test is:
var isEven;
if (x % 2 == 0) {
isEven = true;
} else {
isEven = false;
}
Since 0 type converts to false, and the not (!) operator reverses the truthiness of values and converts the result to boolean, the above can be written:
var isEven = !(x % 2);
There are many ways to iterate over an array, if your task was just to find the element with no odd numbers, I'd use Array.prototype.every, which returns as soon as the test returns false, or Array.prototype.some, which returns as soon as the test returns true.
However, in this case you want to count the number of even numbers in each element and find the first with all even numbers. One way is to iterate over the array and write out the number of even numbers in the element, and also note if its all even numbers. You haven't said what the output is expected to be, so I've just made a guess.
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3], // this last comma affects the array length in some browsers, remove it
];
// Set flag for first element with all even numbers
var foundFirst = false;
// Iterate over each element in passcodes
passcodes.forEach(function(code) {
// Count of even numbers in current array
var evenCount = 0;
// Test each element of code array and increment count if even
code.forEach(function(num) {
if (!(num % 2)) ++evenCount;
});
// If all elements are even and haven't found first yet, write out elements
if (code.length == evenCount && !foundFirst) {
console.log('Passcode (first all even): ' + code.join());
// Set flag to remember have found first all even array
foundFirst = true;
}
// Write count of even numbers in this array
console.log('Even number count: ' + evenCount + ' of ' + code.length + ' numbers.');
});
I have no idea what you meant ...but it does all what i could understand from your question. Hope it will help :)
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3],
];
var aPassCode;
while(aPassCode = passcodes.shift()){
for(var i=0,evenCount=0,totalCount=aPassCode.length;i<totalCount;i++){
if(aPassCode[i] % 2 == 0)evenCount++;
}
if(evenCount == totalCount){
console.log('all digits even here: ' + aPassCode.join(','));
}else{
console.log(aPassCode.join(',') + ' contains ' + evenCount + ' even digits.');
}
}
I'm trying to understand the following solution for finding the largest adjacent product in any given array.
Example:
For inputArray = [3, 6, -2, -5, 7, 3], the output should be
adjacentElementsProduct(inputArray) = 21.
7 and 3 produce the largest product.
Possible solution in JS:
function adjacentElementsProduct(arr) {
return Math.max(...arr.slice(1).map((x,i)=>[x*arr[i]]))
}
I am having a hard time understanding two things:
What do the three dots exactly do and how does this get passed into the function? Is there any way to write this in a more understandable way? I know that is the "spread syntax" feature in ES6, but still don't understand completely.
Why do we insert "1" as argument to slice? My first though was to input "0", because we want to start at the start, then loop through everything, and see which adjacent product is the largest.
I'd appreciate any advice, links and explanations.
Thanks.
Cheers!
1. What do the three dots exactly do and how does this get passed into the function? Is there any way to write this in a more understandable way? I know that is some kind of "spread" feature in ES6, but still don't understand completely.
The Math#max needs a list of numbers as parameters, and map produces an array. The spread syntax is used to convert an array to be expanded to a list of parameters.
const arr = [1, 2, 3];
console.log('max on array', Math.max(arr));
console.log('max on list of parameters', Math.max(...arr));
In this case you can use Function#apply to convert the array to a list of parameters. I find it less readable, however.
const arr = [1, 2, 3];
console.log(Math.max.apply(Math, arr));
2. Why do we insert "1" as argument to slice? My first though was to input "0", because we want to start at the start, then loop through everything, and see which adjacent product is the largest.
Lets break down the iteration order of the 2 arrays.
[3, 6, -2, -5, 7, 3] // inputArray
[6, -2, -5, 7, 3] // inputArray.slice(1)
Now on each iteration of inputArray.slice(1):
x: 6, i = 0, arr[0] = 3
x: -2, i = 1, arr[1] = 6
x: -5, i = 2, arr[2] = -2
Since the inputArray.slice(1) array starts from the 2nd element of the inputArray, the index (i) points to the 1st element of the inputArray. And the result is an array of products of 2 adjacent numbers.
var biggestProduct = inputArray[0] * inputArray[1];
for (i=0; i<inputArray.length-1 ; ++i)
{
console.log(biggestProduct)
if ((inputArray[i] * inputArray[i+1] ) > biggestProduct)
{
biggestProduct = inputArray[i] * inputArray[i+1]
}
}
return biggestProduct;
Note: I've declared a variable that consists of 2 input arrays with index number then starts a for loop that indicates input array with his index number, so by that he will go throw all the index number of the array (one of them raised by one so that they won't be at the same value). and at the end of the code, you have the if statement.
You may simply do as follows;
function getNeigboringMaxProduct([x,...xs], r = -Infinity){
var p = x * xs[0];
return xs.length ? getNeigboringMaxProduct(xs, p > r ? p : r)
: r;
}
var arr = [3, 6, -2, -5, 7, 3],
res = getNeigboringMaxProduct(arr);
console.log(res);
I have been working on a problem on FCC (Free code camp) which requires to scan a 2D array and find largest element from each 1D array and put the result into a 1D array. I came across this solution on GitHub was unable to understand it.
function largestOfFour(arr) {
return arr.map(function(group){
return group.reduce(function(prev, current) {
return (current > prev) ? current : prev;
}, 0);
});
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
OUTPUT IS [5, 27, 39, 1001]
My console.log(arr) gave me: 4,5,1,3,13,27,18,26,32,35,37,39,1000,1001,857,1
How did that 2D array get converted to 1D array when passed as a function parameter?
My console.log(group) gave me: 4,5,1,3 (first time), 13,27,18,26 (second time), 32, 35, 37, 39 (third time) and 1000, 1001, 857, 1 (fourth time).
How was the anonymous function able to take the parameter group as the individual 1D arrays inside the 2D.
Can someone please help.
When you use Array.map it will process each element within the array for example.
[1, 2, 3, 4].map(function (item) { return item; } );
Will just return a new array with [1, 2, 3, 4], but say we double each value we could do it like this.
[1, 2, 3, 4].map(function (item) { return 2 * item; });
Which returns [2, 4, 6, 8] back.
So in your example you have a 2 dimensional array. The Array.map works on the first level. So in each iteration the group is
1st -> [4, 5, 1, 3]
2nd -> [13, 27, 18, 26]
3rd -> [32, 35, 37, 39]
4th -> [1000, 1001, 857, 1]
So the 1st to 4th will then be passed into the Array.reduce function. Reduce just returns a single value based on the array passed in, or better put
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
What is happening in the reduce here is storing the maximum value, it begins with 0, and on the first iteration compares with the value 4. As 4 is larger than 0 it is stored and becomes our new max. It then tests against 5 and as 5 is bigger than 4 it stores that as the new max, and so on.
Once it finishes going through it produces a maximum for that array and gives a Number as the result. So now the first iteration of the map which contained an array is changed to a Number, in this case the first item of the Array produced by Array.map should be 5.
The final output I suspect would be
[5, 27, 39, 1001]
Well the array.map() returns a new array by changing the values of the array you pass to it, in this case we're returning a function itself (array.reduce).
arr.map(function(group))
arr.map takes in a 2D array called 'group' and reads each value inside it, in this case another array. So on the first run of 'map' the first array is [4, 5, 1, 3], we call reduce on it.
group.reduce(function(prev, current)
On the first run of 'reduce' we have prev = 4 and current = 5 ("it starts on second value"), then in:
return (current > prev) ? current : prev;
it asks is 5 bigger than 4?, if so return 5 else return 4. So it returns 5. 5 then is passed into 'prev' for the next run of 'reduce' we have prev = 5 (from last run) and current = 1.
return (1 > 5) ? 1 : 5;
It returns 5 since it's bigger than 1.
return (3 > 5) ? 3 : 5;
It returns 5 since it's bigger than 3. end of group.reduce(), the final returned value '5' is returned to arr.map(), the entire first array [4, 5, 1, 3] is replaced by a single value '5'. next run of arr.map() starts with the second array [13, 27, 18, 26].
I actually did that question on freecodecamp, and I didn't have to use map or reduce. I just read through using "double for loop / array.push / returning the array", although "map / reduce" is a lot cleaner and probably a better way of doing it. Hope that explains it