convert the following code from a for-loop to Array#map - javascript

i am working on simple js function...
I am trying to convert the following code from a for-loop to Array#map
providing my code below in the fiddle..
bnasically i am trying to learn array map..
http://jsfiddle.net/newtdms2/
function doubleAll(numbers) {
var result = [];
result = numbers.map(function(num) {
for (var i = 0; i < numbers.length; i++) {
result.push(numbers[i] * 2)
}
return result;
});
}
module.exports = doubleAll

You don't have to create a for loop in your map, map will call the function callback on each element of the array you pass as parameter. So just try something like :
function doubleAll(numbers) {
return numbers.map(function (num) {
return num * 2;
});
}
Here is the doc for the map method, could be interesting to you !

Your for inside map is not required:
function doubleAll(numbers) {
var result = [];
result = numbers.map(function(num) {
return (num * 2);
});
return result;
}
And simpler can be:
function doubleAll(numbers) {
return numbers.map(function(num) {
return (num * 2);
});
}
Array.prototype.map: will loop once through each element in an array. It receives a callback function as the argument and the callback function takes three arguments, being the first 2:
currentItem: The element being processed in the array in the example above num.
index: The index of the element being processed in the array, in for loop this will be i.

function doubleAll(numbers) {
return numbers.map(num => num*2);
}

Related

why is this for loop not returning the intended output?

This is just an exercise in a course, this app selects a random fruit from the fruits array and then the removeItem() function is supposed to remove that one from the array and returns the modified array, but I'm getting a weird output, and the function is not working.
The problem can be seen here
function randomFruit(importedArray) {
let random = Math.floor(Math.random() * importedArray.length);
return importedArray[random];
}
function removeItem(importedArray, item) {
for (let i = 0; i < importedArray.length; i++) {
if (importedArray[i] === item) {
importedArray.splice(i, 1);
return [...importedArray.slice(0, i), ...importedArray.slice(i + 1)];
} else {
return "not found";
}
}
}
function makeFruitArray() {
var foods = ["🍒", "🍉", "🍑", "🍐", "🍏"];
return foods;
}
let fruitArray = makeFruitArray();
let fruitItem = randomFruit(fruitArray);
let remaining = removeItem(fruitArray, fruitItem);
console.log({fruitArray, fruitItem, remaining});
There are two issues in the removeItem function -
If the random one is not the first item on the array, the function returns not found. It wouldn't run for the second loop at all, as your function returns not found after the first iteration.
The splice method updates the original array. While you are passing the fruitArray to the removeItem method, it gets passed as reference and updating it within the function using splice will update the actual array as well.
The simplest and safest way of removing an item from an array would be -
function removeItem(importedArray, item) {
const filteredArray = importedArray.filter((each) => each !== item);
if (filteredArray.length === 0) return 'Not Found';
return filteredArray;
}
There were two major problems:
Your for loop in removeItem was always returning on the first iteration
You were modifying the initial array as you removed items from it
I've also removed all the unnecessary code used to reproduce your problem. Please read How to Ask to make sure you are helping others help you.
function randomFruit(importedArray) {
let random = Math.floor(Math.random() * importedArray.length);
return importedArray[random];
}
function removeItem(importedArray, item) {
for (let i = 0; i < importedArray.length; i++) {
if (importedArray[i] === item) {
// Don't modify the original array since we want to
// display the original fruits
return [...importedArray.slice(0, i), ...importedArray.slice(i + 1)];
}
}
// Error condition goes outside the loop, not inside.
return null;
}
function makeFruitArray() {
var foods = ["🍒", "🍉", "🍑", "🍐", "🍏"];
return foods;
}
let fruitArray = makeFruitArray();
let fruitItem = randomFruit(fruitArray);
let remaining = removeItem(fruitArray, fruitItem);
console.log({fruitArray, fruitItem, remaining});
As himayan said, the issue was that splice already changes the array.
Here's my solution:
function removeItem(importedArray, item) {
for (let i = 0; i < importedArray.length; i++) {
if (importedArray[i] === item) {
importedArray.splice(i, 1);
break;
}
}
return importedArray;
}
Your remove item function is not working correctly. Instead of writing loops and splicing the array to create a new one you should just use the filter method
function removeItem(importedArray, item) {
let newArray = importedArray.filter(function (element) {
return element !== item;
});
return newArray;
}

How to use currying function to work if one of the argument contains multiple value?

I have a higher order function , though the first case multiply(4,5) works as expected but is it possible to pass multiple argument like multiply(2)(4, 5). In this case the answer is 8, but can a curried function be created in such a way so that it gives 40 as result
function multiply(s) {
return function(b) {
return s * b;
}
}
console.log(multiply(4)(5))
console.log(multiply(2)(4, 5))
You could use rest parameters ... and collect all arguments on both functions and return the reduced result.
function multiply(...a) {
return function(...b) {
return [...a, ...b].reduce((a, b) => a * b);
};
}
console.log(multiply(4)(5)); // 20
console.log(multiply(2)(4, 5)); // 40
console.log(multiply(3, 2)(4, 5)); // 120
function multiply(s) {
return function(b) {
for(key in arguments)s*=arguments[key];
return s;
}
}
console.log(multiply(4)(5))
console.log(multiply(2)(4, 5))
I think its best to use arguments property in your case.
You could do something like this using arguments:
function multiply(s) {
return function () {
return Array.from(arguments).reduce(function(accumulator, currentValue) {
return accumulator * currentValue;
}, s);
}
}
You could do it this way if you have one or more b arguments :
function multiply(s) {
// Will contain the multiplication of all b arguments
var result = 1;
// ...b will return an the array arguments passed
return function(...b) {
// Loop through each of this array and update result
for (var i = 0; i < b.length; i++) {
result *= b[i];
}
// return the final result
return s * result;
}
}
console.log(multiply(4)(5))
console.log(multiply(2)(4, 5))

Returning an array from a higher order function

function map(arr, fn){
for(var i = 0; i <arr.length; i++){
fn(arr[i]);
//some code here
}
}
map([1,2,3,4], function(val){
return console.log(val * 2);
});
I am having trouble trying to get the result into an array form. For example, [2,4,6,8]. I feel like I know how to do it but I'm blanking out.
The callback (fn) should mutate the array value at hand and map should return the array. See the snippet. Furthermore: just use the native Array.map method I'd say (see mdn for that)
function map(arr, fn){
for(var i = 0; i <arr.length; i++){
arr[i] = fn(arr[i]);
}
return arr;
}
console.log(
map([1,2,3,4], function(val){ return val*2; })
);
// but hey, who needs it
console.log([1,2,3,4].map(v => v*2));
Your callback needs to return a new value for each item in array and you need to create a new array of those values
function map(arr, fn){
return arr.map(fn);
}
var res = map([1,2,3,4], function(val){
return val * 2;
});
console.log(res)

JavaScript sum function

I have stacked in the sum of an array. The code is bellow
function User(name,email) {
this.name = name;
this.email = email;
this.cartAmount = [];
this.total = 0;
}
User.prototype = {
constructor: User,
addCart: function(mrp){
this.cartAmount.push(mrp);
},
changeEmail: function(newmail){
this.email = newmail;
},
showCart: function() {
var cart = this.cartAmount.length >0 ? this.cartAmount.join("tk,") : "No product in the cart";
return this.name+" has "+cart+" in his cart.";
},
intotal: function(){
for(var n in this.cartAmount){
this.total += this.cartAmount[n];
return this.total;
}
}
};
athar= new User("Athar Jamil", "atharjamil#gmail.com");
console.log(athar.name);
athar.changeEmail("atharjamil#yahoo.com");
console.log(athar.email);
athar.addCart(20);
athar.addCart(50);
athar.addCart(80);
console.log(athar.intotal());
It shows me only 20 as the result of the sum. What is the problem?
You're returning too early, hence your for loop runs only once and returns the first item in the cart.
Try this instead:
intotal: function(){
for(var n in this.cartAmount){
this.total += this.cartAmount[n];
}
return this.total;
}
Do not use this.total for that. If you call this method several times, your total will increase each time you call it. You should at least put a this.total = 0 at the top of your method.
I personally would have written it like this instead :
intotal: function(){
var out = 0;
for(var n in this.cartAmount){
out += this.cartAmount[n];
}
return out;
}
Using Array.prototype.reduce() you can simplify that function a lot:
intotal: function() {
return this.cartAmount.reduce((a, b)=> a + b)
}
From MDN:
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.
Here you pass an arrow function to the reduce method, which takes two arguments: a and b, and returns sum of them.
intotal function returning the first element of cartAmount array.
Place the return statement of intotal function outside of for loop.
function sum(){
var args = Array.prototype.slice.call(arguments);
return args.reduce(function(pre,curr){
if(!isNaN(curr)){
return pre+curr;
}
else
{
throw Error("Non-Numeric arguments"+curr);
}
},0)
}
var result = sum(12,13,14); //pass any number of parameter to sum
alert("Sum Is:"+result);
https://www.npmjs.com/package/mnjs
First import sum function from mnjs package
<script src="https://cdn.jsdelivr.net/npm/mnjs/browser/index.js"></script>
or
const { sum } = require('mnjs')
or
import { sum } from 'mnjs'
Then use sum function as follow:
const cartAmount = [1, 4, 2]
sum(cartAmount) // returns 7
https://runkit.com/dr-montasir/mnjs-sum-function

Negating Callback Function Return Value

Straightforward question:
Can I negate a callback function that returns true or false o an array.filter() statement? e.g.
//the callback function
function isEven(element, index, array){
if (index%2 == 0 || index == 0){
return true;
}
return false;
}
//what i want to do with that function
//arr[i] is a string
var evens = arr[i].split("").filter(isEven); //works
var odds = arr[i].split("").filter(!isEven); // doesn't work
the above line gives me the error TypeError: false is not a function
Question with some background:
I'm taking on some Hackerrank challenges and i've come across an exercise that requires to take a string and process it, so the output is: The characters with even index values make a new string and the characters in odd index positions make another string , 0 counts as even.
Input
airplane
Output
evens = 'arln'
odds = 'ipae'
I have already solved it by looping through the string, evaluating the index and then pushing the value to the correspondent new array (which i later convert to a string), but it has occurred to me i could be done in a more functional way, using the Array.prototype.filter() function.
now I create a new function that evaluates whether the index number is even or not, and I'd like to use that same function to fill both arrays (evens and odds), like this (now you can refer to the straightforward question part):
var evens = arr[i].split("").filter(isEven); //works
var odds = arr[i].split("").filter(!isEven); // doesn't work
The simplest way to do this would be to just pass an anonymous function which returns the negated result of isEven.
var evens = arr[i].split("").filter(function(el, index, array) {
return !isEven(el, index, array);
});
But you could take this a step further and write a not function which essentially generates the anonymous function for you. Here's an example of such a function.
var input = [0, 1, 2, 3, 4, 5];
function isEven(value) {
return value % 2 === 0;
}
function not(f) {
return function() {
return !f.apply(null, arguments);
}
}
var output = input.filter(not(isEven));
console.log(output);
If you're in an environment that supports rest parameters then you could write your not function like this.
var input = [0, 1, 2, 3, 4, 5];
function isEven(value) {
return value % 2 === 0;
}
function not(f) {
return function(...args) {
return !f.apply(null, args);
}
}
var output = input.filter(not(isEven));
console.log(output);
You would need to pass in an anonymous function and then negate isEven in there:
var odds = arr[i].split("").filter(function(a, index, array) {
return !isEven(a, index, array);
});
Simple Example:
Working Example
function isEven(n) {
return n % 2 === 0;
}
var arr = [0,1,2,3,4,5,6,7,8,9];
var a = arr.filter(isEven);
var b = arr.filter(function(a) {
return !isEven(a);
});
The solution I use is something like this:
var numbers = [0,1,2,3,4,5];
var evens = [];
var odds = [];
function isEvenOrNot(getEven) {
return function(num) {
if (num % 2 == 0 || num == 0){
return true;
}
return false;
}
}
evens = numbers.filter(isEvenOrNot(true));
odds = numbers.filter(isEvenOrNot(false));
console.log(evens); // [0,2,4]
console.log(odds); // [1,3,5]

Categories