Is it safe to modify an array while looping it? - javascript

Is it safe to modify an array while looping it, such as push an element?
I'm using underscore each method

I recommend avoid each unless you absolutely need to cause a side effect for every item in a collection (trigger an event, print out a result, etc.). For simply modifying your collection, there are better ways.
If each added element is only the result of an individual input element, the typical functional pattern would be to flatmap the array, which can be thought of a two steps:
Using map to apply a function that for each element generates an array as a result. The overall result will be an array of arrays.
Using flatten on that array of arrays to get a one dimensional array.
Using underscore or lodash:
var origArray = [1, 2, 3, 4];
var duplicateIf3 = function (val) { return val === 3 ? [val, val] : val; };
_.flatten(origArray.map(duplicateIf3));
// -> [1, 2, 3, 3, 4]
(In typed FP, the function would have to return [val] for values that aren't 3, but flatten doesn't care--it flattens whatever you give it to one dimension.)
If the new element is dependent on all that came before it, you would probably use a reduce or fold instead, with the empty array as the initial value.
var origArray = [1, 2, 3, 4];
origArray.reduce(function (acc, val) { return acc.concat(acc).concat(val); }, []);
// -> [1, 1, 2, 1, 1, 2, 3, 1, 1, 2, 1, 1, 2, 3, 4]
(Sorry I couldn't think of a realistic example, but here every step uses the full output of all previous steps in a pretty simple way for illustrative purposes, and you can see from each value of the original array what's going on. Also note that you can make your own flatten from reduce, if you don't want to use underscore/lodash)
reduce is more general than flatmap, but both methods are able to convert an array into a larger array that some how depends on the first one.
If you're interested in learning more about this, I highly recommend checking out the free (online) Javascript Allongé, by Reg Braithwaite.

I'm not sure what you mean by safe, but you'd have to have a good reason to do it. I played around with it a bit, and here's what I got:
_.each(a, function(el) {
if (el % 2 == 0)
a.push(el + 1);
console.log(el);
});
// logs 1, 2, 3, 4, 5
console.log(a);
// logs [ 1, 2, 3, 4, 5, 3, 5 ]
In this case, there is no negative affect unless you wanted to go through the added elements, but you could find yourself in trickier situations if you're changing the specific elements:
_.each(a, function(el, index) {
a[index + 1] = el - 1;
if (el % 2 == 0)
a.push(el + 1);
console.log(el);
});
// logs 1, 0, -1, -2, -3
It would make more sense to use _.map for most use cases.

Related

Time complexity (Big-O) of converting an array to a Set

So there is multiple ways to convert an Array to a Set in JS.
Example #2 is definitely O(n) since is iterating through all the elements of the array. is that the same case for Example #1? or JS does do some optimization in the background for us?
If yes, are there any downsides to using Example #1?
Example 1
const arr = [ 1, 3, 2, 3, 5 ];
const set = new Set(arr);
console.log(set);
/*
Output: Set { 1, 3, 2, 5 }
*/
Example 2
const arr = [ 1, 3, 2, 3, 5 ];
const set = new Set();
arr.map(item => set.add(item));
console.log(set);
/*
Output: Set { 1, 3, 2, 5 }
*/
It's still O(n); there's no magical way for JS to put all n elements in the Set without actually iterating through all n elements. The only way to get below O(n) would be to skip some of the elements, which is clearly impossible if all of them must be considered for inclusion in the Set.

JS - For Loops Pushing Array

I have an initial array,
I've been trying to change values (orders) by using pop, splice methods inside a for loop and finally I push this array to the container array.
However every time initial array is values are pushed. When I wrote console.log(initial) before push method, I can see initial array has been changed but it is not pushed to the container.
I also tried to slow down the process by using settimeout for push method but this didnt work. It is not slowing down. I guess this code is invoked immediately
I would like to learn what is going on here ? Why I have this kind of problem and what is the solution to get rid of that.
function trial(){
let schedulePattern = [];
let initial = [1,3,4,2];
for(let i = 0; i < 3; i++){
let temp = initial.pop();
initial.splice(1,0,temp);
console.log(initial);
schedulePattern.push(initial);
}
return schedulePattern;
}
**Console.log**
(4) [1, 2, 3, 4]
(4) [1, 4, 2, 3]
(4) [1, 3, 4, 2]
(3) [Array(4), Array(4), Array(4)]
0 : (4) [1, 3, 4, 2]
1 : (4) [1, 3, 4, 2]
2 : (4) [1, 3, 4, 2]
length : 3
When you push initial into schedulePattern, it's going to be a bunch of references to the same Array object. You can push a copy of the array instead if you want to preserve its current contents:
schedulePattern.push(initial.slice(0));
Good answer on reference types versus value types here: https://stackoverflow.com/a/13266769/119549
When you push the array to schedulepattern, you are passing a reference to it.
you have to "clone" the array.
use the slice function.
function trial(){
let schedulePattern = [];
let initial = [1,3,4,2];
for(let i = 0; i < 3; i++){
let temp = initial.pop();
initial.splice(1,0,temp);
console.log(initial);
schedulePattern.push(initial.slice());
}
return schedulePattern;
}
​
You have to know that arrays are mutable objects. What does it mean? It means what is happening to you, you are copying the reference of the object and modifying it.
const array = [1,2,3]
const copy = array;
copy.push(4);
console.log(array); // [1, 2, 3, 4]
console.log(copy); // [1, 2, 3, 4]
There are a lot of methods in Javascript which provide you the way you are looking for. In other words, create a new array copy to work properly without modify the root.
const array = [1,2,3]
const copy = Array.from(array);
copy.push(4);
console.log(array); // [1, 2, 3]
console.log(copy); // [1, 2, 3, 4]
I encourage you to take a look at Array methods to increase your knowledge to take the best decision about using the different options you have.

Find largest adjacent product in array (JavaScript)

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

How does this algorithm work? What does this code mean?

I am trying to figure out what the code below means. I got it from freecodecamp.com and I am doing one of the challenges on there. The challenge is called "Seek and Destroy". I am just one of those people that has to understand what is going on in order for me to proceed, so can someone please explain to me how this code works and what is does from top to bottom?
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments);
return arr.filter(function(element){
return args.indexOf(element) === -1;
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
For example, what is the "element" parameter in the function for .filter() method? How does javascript know what "element" is in the first place? I have been asking people and reading descriptions of solutions, but every solution I read is very vague and is still confusing to me.
Side note: I already know the algorithm removes values from arr, but I just want to know how it does it.
var args = Array.prototype.slice.call(arguments);
This line takes all the arguments given in the function and places them into an array. In this case the value is [[1, 2, 3, 1, 2, 3], 2, 3].
return arr.filter(function(element){
...
});
The .filter() function takes an anonymous function which can have three parameters: element, index, and array. In this case the function iterates through the array arr being [1, 2, 3, 1, 2, 3]. For this function if true is returned the element is kept, if false is return the element is removed from the array.
return args.indexOf(element) === -1
Here we check if the array args has the element element. The .indexOf() method returns the index that the element is found, if it's not found -1 is returned. What this means is if the element is not found it returns true, otherwise it will return false (removing it from the array) if it was found.
Basically the above statements means for each element in the array [1, 2, 3, 1, 2, 3] if it's found in [2, 3] then it's removed. It technically checks [[1, 2, 3, 1, 2, 3], 2, 3], but the first check is against an array compared to an element which will always be false so it might as well be omitted.
Below are some brief comments stating what I mentioned above.
function destroyer(arr) {
// An array of the arguments
var args = Array.prototype.slice.call(arguments);
// For every element in the array arr remove elements found in args
return arr.filter(function(element){
return args.indexOf(element) === -1;
});
}

Choose if array element repeats itself twice -- Javascript [duplicate]

This question already has answers here:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
(97 answers)
Closed 6 years ago.
There is a javascript array
var arr = [0, 1, 2, 2, 3, 3, 5];
I want to choose elements that repeats twice. In this case its 2 and 3. and i want attach them into a variable.
var a = 2, b = 3;
As far as i know there is no built-in function to do that job. How can i do that. Thanks.
You can use filter to get the values that occur twice.
var arr = [0, 1, 2, 2, 3, 3, 5];
var dups = arr.filter ( (v,i,a) => a.indexOf(v) < i );
console.log(dups);
In comments you stated you would only have doubles, but no values that occur more than twice. Note that the above would return a value more than once, if the latter would be the case.
This returns the values in an array, which is how you should work. To put them in separate values can be done as follows:
var [a, b, ...others] = dups;
...but you would have to know how many variables to reserve for that, and it does not make your further program any easier. JavaScript has many nice functions (methods) for arrays, so you should in fact leave them in an array.
There is no built in function to do that indeed.
You will have to loop thought the array and keeping track of the number of occurrences of the elements, while building a response array.
You could filter a sorted array.
var arr = [0, 1, 2, 2, 3, 3, 5],
repeats = arr.filter(function (a, i, aa) {
return aa[i - 1] === a;
});
console.log(repeats);
Most simple way to do this is the following:
var dups = [];
var arr = [0, 1, 2, 2, 3, 3, 5];
arr.forEach(function (v, i, a){
delete arr[i];
if (arr.indexOf(v) !== -1){
dups.push(v);
}
});
console.log(dups);
It's destructive however.

Categories

Resources