This question already has answers here:
Using javascript map with a function that has two arguments
(8 answers)
Closed 6 years ago.
I need to pass an array index as a second parameter to Javascript .map() :
var arr1 = [25,50,75,90]
var arr2 = [1,2,3,4,5]
arr2.map(function(x){
console.log( arr1[index] * x );
});
How can I iterate on arr1 while applying .map() to arr2?
Thanks!
You don't pass a second parameter to map, you pass a second parameter to the function that you pass as a first (and only) parameter to map. When map, in turn invokes that function, it will call it with the current element as the first parameter, and the index of the current element as the second. (Map actually uses a third argument as well, which is the whole array being iterated).
So if you have code like:
arr2.map(function(item, index){
console.log( item, index );
});
You'll get
25 0
50 1
75 2
90 3
if what you need is an array like this:
var arr3 = [25 * 1, 50 * 2, 75 * 3, 90 * 4, 100 * 5];
you may use something like:
var arr1 = [25,50,75,90,100];
var arr2 = [1,2,3,4,5];
var arr3 = arr2.map(function(x, idx){ return x * arr1[idx]; });
Note both arrays should have the same length.
As stated in the Mozilla documentation
The map() function provides a callback which takes three arguments: currentValue, index, array
Related
I'm looking at this example of use of reduce() function.
function add(runningTotal, currentValue) {
return runningTotal + currentValue;
}
var nums = [1,2,3,4,5,6,7,8,9,10];
var sum = nums.reduce(add);
print(sum); // displays 55
Could you give show me some other examples of using reduce() - I'm not sure I fully follow how it works.
Thank you
What reduces does is take an initialValue, a function with 2 essential parameters (can take more) and a list of values. If no initialValue is provided then it's assumed it's the first element of the list. The function is supposed to do something with the previousValue usually used as an accumulator and the nextValue.
So, assume you have a list of values: [1, 2, 3, 4, 5] and the function is supposed to add the 2 parameters and an initialValue of 0.
First step:
0 + 1 = 1
2
3
4
5
Second step:
1 + 2 = 3
3
4
5
Third Step:
3 + 3 = 6
4
5
Fourth Step:
6 + 4 = 10
5
Fifth Step:
10 + 5 = 15 //Final value
As you can see, the input went from a list to a single value, hence the name reduce. In your example, there's no initialValue (that's the second argument), so it's as if started on the second step.
You can set second argument for reduce
function add(runningTotal, currentValue) {
return runningTotal + currentValue;
}
var someInitValue = 10
var nums = [1,2,3,4,5,6,7,8,9,10];
var sum = nums.reduce(add, someInitValue);
console.log(sum); // displays 65
reduce() works by iterating over an array and calling a reductor function (this function is the first argument passed to reduce(). This function has four arguments:
previousValue, which is sort of a 'running total'. this is initially undefined, unless you provide a seed value as the second argument to reduce().
currentValue which is an object in your array
index of the current value in your array
array, the array itself
when your reductor function is called, its return value becomes the new previousValue argument for next time the reductor function is called. that's the magic. after the reductor function is called and given the very last object in the array, its return value will be the return value of reduce().
honestly, a lot of the examples you'll see (like using reduce() to sum up a bunch of integers) are pretty easy to do with a for() loop. its real value is when you're doing functional programming.
You can also use reduce to do things like generate some kind of stream cipher.
var plaintext = "thisisaplaintext";
var chars = plaintext.split('');
var result = '';
function encrypt(runningTotal, currentValue){
var newVal = ((runningTotal + (""+runningTotal).charCodeAt()-32) % 94)+32
result = result + String.fromCharCode(newVal)
return newVal;
}
chars.reduce(encrypt, 15 /*any arbitrary starting value*/);
console.log(result);
Basically, anything that can be made with a combination of independent calculations or anything that requires some rolling total. It's nothing that you couldn't already do with a for loop, but it looks cleaner.
Let's say I'm given an array. The length of this array is 3, and has 3 elements:
var array = ['1','2','3'];
Eventually I will need to check if this array is equal to an array with the same elements, but just twice now. My new array is:
var newArray = ['1','2','3','1','2','3'];
I know I can use array.splice() to duplicate an array, but how can I duplicate it an unknown amount of times? Basically what I want is something that would have the effect of
var dupeArray = array*2;
const duplicateArr = (arr, times) =>
Array(times)
.fill([...arr])
.reduce((a, b) => a.concat(b));
This should work. It creates a new array with a size of how many times you want to duplicate it. It fills it with copies of the array. Then it uses reduce to join all the arrays into a single array.
The simplest solution is often the best one:
function replicate(arr, times) {
var al = arr.length,
rl = al*times,
res = new Array(rl);
for (var i=0; i<rl; i++)
res[i] = arr[i % al];
return res;
}
(or use nested loops such as #UsamaNorman).
However, if you want to be clever, you also can repeatedly concat the array to itself:
function replicate(arr, times) {
for (var parts = []; times > 0; times >>= 1) {
if (times & 1)
parts.push(arr);
arr = arr.concat(arr);
}
return Array.prototype.concat.apply([], parts);
}
Basic but worked for me.
var num = 2;
while(num>0){
array = array.concat(array);
num--}
Here's a fairly concise, non-recursive way of replicating an array an arbitrary number of times:
function replicateArray(array, n) {
// Create an array of size "n" with undefined values
var arrays = Array.apply(null, new Array(n));
// Replace each "undefined" with our array, resulting in an array of n copies of our array
arrays = arrays.map(function() { return array });
// Flatten our array of arrays
return [].concat.apply([], arrays);
}
console.log(replicateArray([1,2,3],4)); // output: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
What's going on?
The first two lines use apply and map to create an array of "n" copies of your array.
The last line uses apply to flatten our recently generated array of arrays.
Seriously though, what's going on?
If you haven't used apply or map, the code might be confusing.
The first piece of magic sauce here is the use of apply() which makes it possible to either pass an array to a function as though it were a parameter list.
Apply uses three pieces of information: x.apply(y,z)
x is the function being called
y is the object that the function is being called on (if null, it uses global)
z is the parameter list
Put in terms of code, it translates to: y.x(z[0], z[1], z[2],...)
For example
var arrays = Array.apply(null, new Array(n));
is the same as writing
var arrays = Array(undefined,undefined,undefined,... /*Repeat N Times*/);
The second piece of magic is the use of map() which calls a function for each element of an array and creates a list of return values.
This uses two pieces of information: x.map(y)
x is an array
y is a function to be invoked on each element of the array
For example
var returnArray = [1,2,3].map(function(x) {return x + 1;});
would create the array [2,3,4]
In our case we passed in a function which always returns a static value (the array we want to duplicate) which means the result of this map is a list of n copies of our array.
You can do:
var array = ['1','2','3'];
function nplicate(times, array){
//Times = 2, then concat 1 time to duplicate. Times = 3, then concat 2 times for duplicate. Etc.
times = times -1;
var result = array;
while(times > 0){
result = result.concat(array);
times--;
}
return result;
}
console.log(nplicate(2,array));
You concat the same array n times.
Use concat function and some logic: http://www.w3schools.com/jsref/jsref_concat_array.asp
Keep it short and sweet
function repeat(a, n, r) {
return !n ? r : repeat(a, --n, (r||[]).concat(a));
}
console.log(repeat([1,2,3], 4)); // [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
http://jsfiddle.net/fLo3uubk/
if you are inside a loop you can verify the current loop index with the array length and then multiply it's content.
let arr = [1, 2, 3];
if(currentIndex > arr.length){
//if your using a loop, make sure to keep arr at a level that it won't reset each loop
arr.push(...arr);
}
Full Example:
https://jsfiddle.net/5k28yq0L/
I think you will have to write your own function, try this:
function dupArray(var n,var arr){
var newArr=[];
for(var j=0;j<n;j++)
for(var i=0;i<arr.length;i++){
newArr.push(arr[i]);
}
return newArr;
}
A rather crude solution for checking that it duplicates...
You could check for a variation of the length using modulus:
Then if it might be, loop over the contents and compare each value until done. If at any point it doesn't match before ending, then it either didn't repeat or stopped repeating before the end.
if (array2.length % array1.length == 0){
// It might be a dupe
for (var i in array2){
if (i != array1[array2.length % indexOf(i)]) { // Not Repeating }
}
}
My question is about the map method of arrays in JavaScript.
You can pass it a function that takes a second argument, the index of the current element of the array being processed, but... to what purpose? What happens when you do it and what's the difference when you don't?
What would you use this feature for?
The index of the current item is always passed to the callback function, the only difference if you don't declare it in the function is that you can't access it by name.
Example:
[1,2,3].map(function(o, i){
console.log(i);
return 0;
});
[1,2,3].map(function(o){
console.log(arguments[1]); // it's still there
return 0;
});
Output:
0
1
2
0
1
2
Demo: http://jsfiddle.net/Guffa/k4x5vfzj/
Sometimes the index of the element matters. For example, this map replaces every second element with 0:
var a = [1, 2, 3, 4, 5, 6];
var b = a.map(function(el, index) {
return index % 2 ? 0 : el;
});
console.log(b);
Output:
[1, 0, 3, 0, 5, 0]
Here is a description of of the map function:
arr.map(callback[, thisArg])
callback
Function that produces an element of the new Array, taking three arguments:
currentValue
The current element being processed in the array.
index
The index of the current element being processed in the array.
array
The array map was called upon.
The map function takes a callback function as argument (and not an index as argument, as originally stated in the question before it was edited). The callback function has an index as a parameter - the callback is called automatically, so you don't provide the index yourself. If you only need the current value, you can omit the other parameters.
I want to generate a proportional array of numbers between 0 and 1 with an array of sales that has different size values.
For example if I have the values [1, 80, 2000] it would be ok an array like [0.1, 0.4, 1].
a modern functional approach:
var r=[1, 80, 2000] ;
r.map(function(a){
return a/this;
}, Math.max.apply(0,r) );
//==[0.0005,0.04,1]
i think math was off in OP...
edit: details on what's going on here:
The problem is broken down into two steps.
find the largest number in the Array
compute each Array item as a portion of the largest item
For the first step, JS provides the Math.max function. To use an argument-based function with an array, the function's apply() method is used, and 0 is passed as "this", but it's not really used; it just needs to be something.
The second step compares each item to the number found in step #1, using the Array.map method to iterate the Array and return the result of an operation upon each item in the Array. Since Array.map() can accept an optional "this" argument, the largest number from step #1 is passed as "this" to avoid a performance-robbing function closure.
though it is not clear, what should be the relationship between original array and the generated array. Am assuming you want to create what fraction the item is of the total sum (proportion):
try this:
function generateProportion(arr){
//find out the total sum..
var total = 0;
for(var k=0;k <arr.length;k++)
total += arr[k];
//push the ratios into the new array with double precison..
var newArr = new Array();
for(var i=0;i< arr.length; i++)
newArr.push((arr[i]/total).toFixed(2));
console.log(newArr);
return newArr;
}
and call it like this:
var a = [1, 80, 2000];
generateProportion(a);
see this fiddle
I have some simple jQuery code:
var response = Array()
$('.task-list').each(function() {
response.concat(response,$('#' + this.id).sortable('toArray'));
}
);
console.log(response);
The problem I'm having is that I think I'm using concat improperly- the result is an empty array. When I use array push, it works correctly.
You have to set response to the newly formed array, as described in the specification. You currently don't use the return value at all.
The specification says that for .concat, the array is not altered, but the new array is returned:
When the concat method is called with zero or more arguments item1, item2, etc., it returns an array containing the array elements of the object followed by the array elements of each argument in order.
Compare with .push, which says the current array is altered, and that something else is returned instead (the new length):
The arguments are appended to the end of the array, in the order in which they appear. The new length of the array is returned as the result of the call.
So:
response = response.concat($('#' + this.id).sortable('toArray'));
Concat returns the concatenated array, you want this instead
response = response.concat($('#' + this.id).sortable('toArray'));
Simple example
var a = [1,2];
var b = [3,4];
a = a.concat( b ); // result is [1,2,3,4] which is correct
If you do the following
a = a.concat( a , b ); // result is [1, 2, 1, 2, 3, 4] not what you want.