user14622124
user14622124

Reputation:

How to solve this with high order functions?

I need to know how to solve this problem I've read from internet.

With a given array I need find all uniques elements and minus than 10. Then do the sumatory of all of them. And later multiply each array value by this number (the sumatory).

I'm assuming I can use reduce to do the sumatory and map to multiply but I don't know really how it works and I'm stuck. Also to find the unique element is not easy.

I have the entry values and expected ones.

Input, expected  
[1], [1]  
[1, 1, 2], [2, 2, 4]  
[0, 0, 1, 2, 1], [0, 0, 2, 4, 2]  
[0, 10, 1, 1, 20, 3, 40, 3], [0, 0, 0, 0, 0, 0, 0, 0]  
[0, 1, 1, 2, 4, 11], [0, 6, 6, 12, 24, 66]  
[10, 1, 1, 1], [0, 0, 0, 0]  
[10, 11, 1, 2, 3, 4], [100, 110, 10, 20, 30, 40]

I'm trying a few things, but the main problem is I don't understand the syntaxis I think. I know how to solve this iterating through a loop, but I want learn by high order functions.

This is not a school project, I'm learning about this, so I don't need only the solution, I would like to understand, thanks.

What I tried is apply map like this. And also filter and reduce

var input = [0, 0, 1, 2, 1]
var output = [0, 0, 2, 4, 2]

var map, reduce, filter;
map = input.map(multiplyFunction(first,second))

function multiplyFunction(first,second){
    return first*second
}

Upvotes: 4

Views: 136

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386680

You could separate the wantes result into two parts, one for getting the factor of the unique values and another to map new values with the factor.

getSumOfUnique

The factor function iterates the values and continues for unwanted values.

This function uses an object to count seen values and takes a variable for summing the unique values.

This happens in two ways:

  1. add the value if the value is never seen before
  2. subtract the value if the value is seen only once.

At the end return sum as factor for the calling function.

multiply

The mapping function gets the factor first and maps a new product with Array#map.

function getSumOfUnique(array) {
    let seen = {},
        sum = 0;
    
    for (const value of array) {
        if (value >= 10) continue;
        if (!seen[value]) {
            seen[value] = 1;
            sum += value;
            continue;
        }
        if (seen[value] === 1) {
            seen[value]++;
            sum -= value;
        }
    }
    return sum;
}

function multiply(array) {
    const factor = getSumOfUnique(array);
    return array.map(value => value * factor);
}

console.log(...multiply([1]));
console.log(...multiply([1, 1, 2]));
console.log(...multiply([0, 0, 1, 2, 1]));
console.log(...multiply([0, 10, 1, 1, 20, 3, 40, 3]));
console.log(...multiply([0, 1, 1, 2, 4, 11]));
console.log(...multiply([10, 1, 1, 1]));
console.log(...multiply([10, 11, 1, 2, 3, 4]));

Finally a functional approach by using

  • less10 for checking if a value is less than 10 for Array#filter,
  • unique for getting only unique values by checking the index of the value for filter as well,
  • add a function which adds to values, later used for Array#reduce
  • multiplyBy, an IIFE (immediately-invoked function expression) with a closure over the factor, later used for map,
  • getArray a function which holds all parts and mapps the array with a previously calculated factor.

const
    less10 = value => value < 10,
    unique = (v, _, a) => a.indexOf(v) === a.lastIndexOf(v),
    add = (a, b) => a + b,
    multiplyBy = factor => value => factor * value,
    getArray = array => array.map(multiplyBy(array
        .filter(less10)
        .filter(unique)
        .reduce(add, 0)
    ));

console.log(...getArray([1]));
console.log(...getArray([1, 1, 2]));
console.log(...getArray([0, 0, 1, 2, 1]));
console.log(...getArray([0, 10, 1, 1, 20, 3, 40, 3]));
console.log(...getArray([0, 1, 1, 2, 4, 11]));
console.log(...getArray([10, 1, 1, 1]));
console.log(...getArray([10, 11, 1, 2, 3, 4]));

Upvotes: 4

J.F.
J.F.

Reputation: 15207

Hello and welcome to StackOverflow.

First of all, I think a good point to start to understand the syntaxis is checking the w3 examples: filter, map, reduce. Or mozilla examples: filter, map, reduce

Try these examples and try to understand each step.

Your exercise need for these three functions, so as an overview, we can define each one in this way (maybe this is so informal):

  • Filter: Use a filter to create a new array.
  • Map: Do something thorugh every value into the array (i.e. map the values from one array to another).
  • Reduce: Reduce the array to an unique element.

So... for your exercise.

The phrases itself explain what function to use. Check this:

I need find all uniques elements and minus than 10

It means: "I need to use filter with a function like return unique && x < 10."

Then do the sumatory

So... reduce to an unique element. Is like "Then do reduce with a function like return currentValue + nextValue

And later multiply each array value by this number

That's like: "And later map every value as value*=sumatory"

And that's all! Easy, right? Now let's translate into code.

Let's assuming you have an array like this: [10, 11, 1, 2, 3, 4] (the last into the example)

First you need to find the unique value and < 10 using filter.
The unique position has a trick. If you compare the first and last index for a number and it's the same value, then... is unique. So the function is like this

var array = [10, 11, 1, 2, 3, 4]
var filter = array.filter(x => (array.indexOf(x) === array.lastIndexOf(x) && x < 10))
console.log(filter) // [ 1, 2, 3, 4 ] 

But there is no only one way to do this. You can create a Set to no repeat values, count every value to get those with count=1 or whatever, is your decission. I've chosen this because I think is the best way.

The syntaxis is easy to read: For each value into the array, named x then do => the function. In this case compare the index and compare is <10.

Note that in yor example you are missing (x) => so you can't pass variables to your function.

Next step... reduce

var reduce = filter.reduce((a, b) => a + b, 0)
console.log(reduce) // 10

Easy. Use reduce into the output array.
The sintaxys here is: "With the current value a and next value b, do => the function a+b starting at 0". In other words... do the sumatory.

The last step: Map.

var map = array.map((m) => {
    return m * reduce
})
console.log(map) // [ 100, 110, 10, 20, 30, 40 ]

Here you are saying: "For every value into the array, m, do a function =>{...} where multiply by the sumatory m * reduce."

AND NOW: DO IT TOGETHER!!

Yes, the (really) last step, only replace variables for functions.

Where you see reduce put filter.reduce((a, b) => a + b, 0).
And where there is filter set array.filter(x => (array.indexOf(x) === array.lastIndexOf(x) && x < 10))

var map = array.map((m) => {
    return m * (array.filter(x => (array.indexOf(x) === array.lastIndexOf(x) && x < 10))).reduce((a, b) => a + b, 0)
})

And that's all.

Hope it helps to understand a little bit how to use the functions and how to solve these problems.

After see what have you try, check the examples and note that you need to get the variables using (var) =>.

And a snippet

var array = [10, 11, 1, 2, 3, 4]
var map = array.map((m) => {
    return m * (array.filter(x => (array.indexOf(x) === array.lastIndexOf(x) && x < 10))).reduce((a, b) => a + b, 0)
})
console.log(map)

Upvotes: 3

WildWilyWilly
WildWilyWilly

Reputation: 141

Welcome V.D. I am a JS noob as well but this, I think I get ;)

You wanna filter out your values first, so the Array.filter method allows you to do so without any cumbersome for loops, like this:

const array = [10, 11, 3, 20, 5];
const lesserThanTen = array.filter(element => element < 10);
console.log(lesserThanTen) //[3, 5]

the syntax of the reduce() function requires you to first define the function you want to apply to the items in your array, like this:

function myFunc(total, num) {
  return total + num; // this will return the sum of the two numbers it receives
} 
// The reduce() method applies this to the array until it is just a single value

var reducedNumbers = lesserThanTen.reduce(myFunc);

Once ou have the filtered array and the summatory, you can proceed to multiply everything by this latter number.

var x = lesserThanTen.map(multiplyBySummatory)

This should be enough for you to get there ;)

Upvotes: 2

Related Questions