From the following thread (Multiplying an array with a single value by a number?) I got the information that it is not possible to multiply a number to all elements within an array by executing [1, 2]*3. But since I have to do this I was wondering if there is an smart way of doing this?
I know I could write a function which iterates through all elements and multiply a number to each element manually. But I was wondering if there is a smarter way out there?
Maybe there are some libraries out there which implements some math functions where I can multiply a number to all elements of an array?
Or do you think the map function of Array can be used for this purpose?
You can indeed use the map function:
function multiply(input) {
return input * 3;
}
var myArray = [1, 2];
var myNewArray = myArray.map(multiply);
What this does is perform a function you provide on each element in the array, and return a new array with the results.
If you're already using jQuery, you can make it a little more concise with the each function:
$.each(myArray, function(index, value) {
myArray[index] = value * 3;
});
This changes the existing array. Although, using the plain-JS approach, you could do myArray = myArray.map(multiply); if you don't want a new variable.
I made a jsFiddle as an example.
This is easy with a library like math.js, which comes with matrix support. You could do something like:
var result = math.multiply([1, 2], 3);
or using the expression parser:
var result = math.eval('[1, 2] * 3');
Similar to Jos de Jong's answer, if you are using numericjs you can do
var result = numeric.mul([1, 2], 3);
To give the result [3, 6].
You have not defined your array as an array variable: Just do as following:
function times2(theArray){
var newArray = [];
for (i = 0; i < theArray.length; i++) {
newArray.push(theArray[i] * 2);
}
return newArray;
}
document.write("Array double = ",times2([1,2,3,4,5]).toString() , "<br>");
Now it does not matter how many elements you have in your array, it multiplies them by 2. You can choose any number instead of 2.
Related
Using Descriptive way
//Declare variables
var arr1 = [1,2,3];
arr2 = [];
//Immediate Invoked Functions
(function(){
for(var i = 0 ; i<arr1.length ; i++){
arr2.push(3 * arr1[i]);
}
//logging the values
console.log(arr2);
console.log(arr1);
})();
Using Functional Programming and First Class function
//Declare variables
var arr1 = [1,2,3];
//creating a function to push values
function mapEachArrayValue(arr,fn){
var newArr=[];
for(var i=0; i<3 ; i++){
newArr.push(fn(arr1[i]));
}
return newArr;
}
var arr2 = mapEachArrayValue(arr1,function(item){
return 3 * item;
})
why do we need to use functional programming in this example? It's works fine with normal descriptive way.
You're doing this wrong. You can shorten this using the inbuilt map function. For example,
let arr1 = [1, 2, 3]
let arr2 = arr1.map(item => item * 3)
console.log(arr2) // [3, 6, 9]
This is much more concise. This doesn't use any external iterators. This also doesn't mutate the original array(though you also don't mutate it in your example). This is more readable if you know what map is.
So this is how map works: You call map on an Array and pass it a function. This is where a function being first class comes into picture. You're passing it to another function. Map basically takes this function and the array and calls this function on each entry in the array. The value your function returns is stored in another array at the corresponding indices and this newly constructed array is returned by map.
Head over to MDN Docs to learn more about map, how it works and some more examples. There are other functions like filter, reduce, etc that once you learn are very hard to not use while writing JS. Read through all the examples for these three functions and try to apply them when you code.
I'll just put this code here so that you can see how concise and expressive it can be to use these functions once you understand their syntax and what they do.
let myArr = [1,2,3,4,5,6,7,8,9]
let sumOfDoubleOfOddNumbers = myArr.filter(num => num % 2)
.map(num => num * 2)
.reduce((acc, currVal) => acc + currVal, 0);
First we filter out all numbers that do not pass the test. Then we double all these filtered numbers. Finally using a reducer and a starting value we reduced this array down to a final value. In this process, we used 3 different functions that were passed as arguments(reiterating on the functions being first class citizens point).
I am trying to learn how to optimize javascript in the most efficient way possible...
I would assume it would be good practice to avoid creating references to properties wherever possible.
In PHP, if i have this Array:
$dataArray = [4,6,8];
To modify this array's values, i can write a foreach loop to return a reference to the value in that array, rather than a copy, using an ampersand like so:
foreach ($dataArray as &$value) {
$value = $value / 2;
}
unset($value); // if im not mistaken, this is just cleanup
// $dataArray will now = [2,3,4]
Is the following the most efficient way to achieve the same result in Javascript?
var dataArray = [4,6,8];
for (i = 0; i < dataArray.length; i++) {
dataArray[i] = dataArray[i] / 2;
}
// if so, is there anything i should do to clean up the for loop to avoid memory leaks?
You could use Array#forEach with parameters for index and the array. Then assign a new value to the item with the same index.
var array = [4, 6, 8];
array.forEach(function (_, i, aa) {
aa[i] /= 2;
});
console.log(array);
Just for completeness, you could generate a new array with Array#map and assign it to the variable.
var array = [4, 6, 8];
array = array.map(function (a) {
return a / 2;
});
console.log(array);
As I'm learning the forEach() method in JavaScript, I have several questions related to it.
Currently I've written the following piece of code:
var arr = [1,2,3,4,5,6];
arr.forEach(function(elem, idx, arr){
elem=elem*2;
});
alert(arr); // "1,2,3,4,5,6"
My goal is to simply multiply each element in arr by 2, however when I use alert to examine the final values it seems that values inside arr hasn't been modified. What's the problem here?
Also I'm a little confused about the 3 arguments that forEach's function takes. First, is it required to pass in 3 arguments? What will happen if one doesn't provide exactly 3 arguments? Some tutorials I've looked at seem to provide only 1 argument, yet the explanation wasn't clear. Second, do the names of arguments matter (e.g. e, elem, or element)?
Thank you.
Your approach
You are not assigning new value to anything else but the elem, which is only in callback's scope. Modify your code, so that the elem * 2 is assigned to arr[idx]. Working example:
var arr = [1, 2, 3, 4, 5, 6];
arr.forEach(function(elem, idx) {
arr[idx] = elem * 2;
});
document.body.textContent = arr;
Better approach
For tasks like that however, you should use map:
var arr = [1, 2, 3, 4, 5, 6];
arr = arr.map(function(num) {
return num * 2;
});
document.body.textContent = arr;
The array is not getting modified cus you are not modifying it. To do that update the code as following.
var arr = [1,2,3,4,5,6];
arr.forEach(function(elem, idx, arr){
arr[idx] = elem*2
});
console.log(arr);
If you check the console you would see the updated arr.
you cannot edit the array in place by returning the new value or changing elem. You can however use the idx variable like arr[idx] = elem * 3 or use the map function.
you can omit the parameters that you don't need
you can name them whatever you want
For first problem, just use map
var arr = [1,2,3,4,5,6];
arr = arr.map(function(elem){
return elem*2;
});
alert(arr); // "2,4,6,8,10,12"
arguments is optional, and names doesn't matter at all.
The arguments are optional.
idx lets you know the index of the array element you are currently evaluating.
arr, is the array you are evaluating.
so elem == arr[idx]
I'm trying to solve a freeCodeCamp exercise with this goal:
Write a function that takes two or more arrays and returns a new array
of unique values in the order of the original provided arrays.
In other words, all values present from all arrays should be included
in their original order, but with no duplicates in the final array.
The unique numbers should be sorted by their original order, but the
final array should not be sorted in numerical order.
So what I do is concatenate all the arguments into a single array called everything. I then search the array for duplicates, then search the arguments for these duplicates and .splice() them out.
So far everything works as expected, but the last number of the last argument does not get removed and I can't really figure out why.
Can anybody please point out what I'm doing wrong? Please keep in mind that I'm trying to learn, so obvious things probably won't be obvious to me and need to be pointed out. Thanks in advance.
function unite(arr1, arr2, arr3) {
var everything = [];
//concat all arrays except the first one
for(var x = 0; x < arguments.length; x++) {
for(var y = 0; y < arguments[x].length; y++) {
everything.push(arguments[x][y]);
}
}
//function that returns duplicates
function returnUnique(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
//return duplicates
var dupes = returnUnique(everything);
//remove duplicates from all arguments except the first one
for(var n = 1; n < arguments.length; n++) {
for(var m = 0; m < dupes.length; m++) {
if(arguments[n].hasOwnProperty(dupes[m])) {
arguments[n].splice(arguments[n].indexOf(dupes[m]), 1);
}
}
}
//return concatenation of the reduced arguments
return arr1.concat(arr2).concat(arr3);
}
//this returns [1, 3, 2, 5, 4, 2]
unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);
Looks like you overcomplicated it a bit ;)
function unite() {
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
}
res = unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]);
document.write('<pre>'+JSON.stringify(res));
Explanations
We split the problem into two steps:
combine arguments into one big array
remove non-unique elements from this big array
This part handles the first step:
[].concat.apply([], arguments)
The built-in method someArray.concat(array1, array2 etc) appends given arrays to the target. For example,
[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]
If our function had fixed arguments, we could call concat directly:
function unite(array1, array2, array3) {
var combined = [].concat(array1, array2, array3);
// or
var combined = array1.concat(array2, array3);
but as we don't know how many args we're going to receive, we have to use apply.
someFunction.apply(thisObject, [arg1, arg2, etc])
is the same as
thisObject.someFunction(arg1, arg2, etc)
so the above line
var combined = [].concat(array1, array2, array3);
can be written as
var combined = concat.apply([], [array1, array2, array3]);
or simply
var combined = concat.apply([], arguments);
where arguments is a special array-like object that contains all function arguments (actual parameters).
Actually, last two lines are not going to work, because concat isn't a plain function, it's a method of Array objects and therefore a member of Array.prototype structure. We have to tell the JS engine where to find concat. We can use Array.prototype directly:
var combined = Array.prototype.concat.apply([], arguments);
or create a new, unrelated, array object and pull concat from there:
var combined = [].concat.apply([], arguments);
This prototype method is slightly more efficient (since we're not creating a dummy object), but also more verbose.
Anyways, the first step is now complete. To eliminate duplicates, we use the following method:
combined.filter(function(elem, index) {
return combined.indexOf(elem) === index;
})
For explanations and alternatives see this post.
Finally, we get rid of the temporary variable (combined) and chain "combine" and "dedupe" calls together:
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
using the 3rd argument ("this array") of filter because we don't have a variable anymore.
Simple, isn't it? ;) Let us know if you have questions.
Finally, a small exercise if you're interested:
Write combine and dedupe as separate functions. Create a function compose that takes two functions a and b and returns a new function that runs these functions in reverse order, so that compose(a,b)(argument) will be the same as b(a(argument)). Replace the above definition of unite with unite = compose(combine, dedupe) and make sure it works exactly the same.
You can also try this :
var Data = [[1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]]
var UniqueValues = []
for (var i = 0; i < Data.length; i++) {
UniqueValues = [...new Set(UniqueValues.concat(Data[i]))]
}
console.log(UniqueValues)
For the life of me, I just can't figure out what I'm doing wrong here.
I'm trying to use both the reduce and concat array methods to take all of the values of a 2d array and combine them into a single value (basically condense them into a single array and then sum them up).
The problem that I keep running into is that when I try to make a for/loop to concat each array element, the argument that I'm passing into the function is not being recognized as an array, thus my call to .concat() is failing. I've placed a console.log() at the beginning of the function to see if the element is being recognized as the first array element in the 2d array, and it's coming up as "1"(?).
I tried another test outside of the function, and it logs as the actual array element. What am I doing wrong here? code below:
var arrays = [[1, 2, 3], [4, 5], [6]];
var myArray = arrays[0]; // Test
console.log(myArray); // Test
var flatArray = arrays.reduce(function(arrays)
{
console.log(arrays[0]); // Test
for (var i = 0; i < arrays.length - 1; i++)
{
arrays[0].concat(arrays[i+1]);
}
return arrays;
});
console.log(flatArray);
This is the output that I keep getting:
Array [ 1, 2, 3 ]
1
TypeError: arrays[0].concat is not a function
It's almost seems like array is being converted to a number-type when inside the function...?
You have an error in your code here:
var flatArray = arrays.reduce(function(param) {})
that param will be an element of your arrays vector.
Check this https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
You are using .reduce() incorrectly and you don't even need to use it to flatten an array. You can just do this:
var flatArray = [].concat.apply([],arrays);
Working demo: http://jsfiddle.net/jfriend00/wfjyfp42/
To understand .reduce(), the callback you pass it gets four arguments (see MDN reference). The first two arguments are important in using .reduce() correctly:
callback(previousValue, currentValue, index, array)
The previousValue is the accumulated value so far in the reduction. The currentValue is the next element of the array that is being iterated. The last two arguments do not need to be used if not needed.
Your code is only using the previousValue so it is never looking at the next item in the array as passed in by .reduce().
You could make a solution work using .reduce() like this:
var flatArray = arrays.reduce(function(previousValue, currentValue) {
return previousValue.concat(currentValue);
}, []);
Working demo: http://jsfiddle.net/jfriend00/2doohfc5/
Reduce performs an operation on two elements.
var sum = [[1, 2, 3], [4, 5], [6]].reduce(function(a, b) {
return a.concat(b);
}).reduce(function(a, b) {
return a + b;
});