How to chunk js array and apply math function on the chunks? - javascript

What is the fastest way to split an array into small chunks, then apply math function in the small array?
The math function could be simple such as the total of the chunk mod 26.
What I mean, I have array [1,2,3,4,5,6], I need to create chunks of it to have every 3 elements in 1 chunk, so I will get from the main array:
[1,2,3]
[4,5,6]
The apply total of [1,2,3] 6mod26, and [4,5,6] 15mod26.
So, the final array will be [6,15].
Also, ignore the remaining of the main array if the remaining elements less the required chunk size, or add it in array alone.
simple way ..
[1,2,3,4,5,6,7] => chunk1[1,2,3] , chunk2[4,5,6] , chunk3[7]
result = [ (total([1,2,3]) mod 26 ) , (total([4,5,6]) mod 26 ) ]
I hope this is clear.

You could slice the array with the wanted size and reduce the array by adding all items and push the result of the remainder value.
var add = (a, b) => a + b,
array = [1, 2, 3, 4, 5, 6],
size = 3,
result = [],
i = 0;
while (i < array.length) {
result.push(array.slice(i, i += size).reduce(add) % 26);
}
console.log(result);

Sorry, but I don't know how to make more clear than this, simple way:
1. chunk the array
2. get the total sum of each chunk
3. mod the total sum of each chunk
4. create a new array from the mod.
I reached to away, but I think there is a better way:
splitArrayIntoChunksOfLen(arr, len) {
let chunks = [], i = 0, n = arr.length;
while (i < n) {
chunks.push(arr.slice(i, i += len));
}
return chunks;
}
let add = this.splitArrayIntoChunksOfLen(this.stringsArrays, 5)
let newAdd = add.map(function (item) {
return item.reduce(function (acc, curr) {
acc += curr;
return acc - 92 * Math.floor(acc / 92);
}, 0)
});

Related

Is it possible to optimize my js hashmap challenge to merge two .forEach loops?

Is it possible to merge the two arr.forEach() functions in my code together?
Here is my code:
function countTriplets(arr, r) {
let count = 0;
let freq = {};
let arrSum = [];
arr.forEach((num) => {
freq[num] ? freq[num]++ : freq[num] = 1;
})
arr.forEach((number) => {
let sum = freq[number/r] * freq[number * r];
if(!isNaN(sum)) {
arrSum.push(sum);
}
});
console.log("freq", freq);
console.log("arrSum", arrSum);
count = arrSum.reduce((a, b) => a + b);
return count;
}
If you are wondering what my code is about. It's to count the amount of triplets in an array such as [1, 5, 5, 25, 125]. It's for HackerRank challenge: https://www.hackerrank.com/challenges/count-triplets-1/problem.
The main challenge posted in this link is:
You are given an array and you need to find number of tripets of
indices (i, j, k) such that the elements at those indices are in
geometric progression for a given common ratio r and i < j < k
.
For example, arr = [1, 4, 16, 64] . If r = 4, we have [1, 4,
16] and [4, 16, 64].
I got my solution/inspiration from watching this: https://www.youtube.com/watch?v=tBFZMaWP0W8.
As mentioned in #Bergi's answer, you can't combine the two for loops.
But I believe you can eliminate this step:
count = arrSum.reduce((a, b) => a + b);
Here's a version of the algorithm in the question that eliminates the final arrSum.reduce and uses reduce in place of forEach.
function countTriplets(arr, r) {
const freq = arr.reduce((freq, num) => {
freq[num] = freq[num] ? freq[num] + 1 : 1;
return freq;
}, {});
console.log('freq', freq);
const count = arr.reduce((sum, number) => {
const triplets =
freq[number / r] && freq[number * r]
? freq[number / r] * freq[number * r]
: 0;
return sum + triplets;
}, 0);
return count;
}
const arr = [1, 5, 5, 25, 125];
const count = countTriplets(arr, 5);
console.log(`count:`, count);
There's also the case where r == 1. That's a faster calculation, as the triplet count for each number is just the combinations formula:
freq! freq * (freq-1) * (freq-2)
triplets = ---------------- = ----------------------------
3! * (freq-3)! 6
Where n! means factorial of n.
Is it possible to merge the two arr.forEach() functions in my code together?
No. The algorithm relies on all the counts being computed first and evaluated second.
Is it possible to optimize my solution by merging two loops?
No. You won't achieve a better time complexity by merging them, it's still a linear solution (which is as good as it gets).
If you want to improve your code, I'd suggest to
use a Map instead of an object, it's better suited for this purpose
don't use isNaN to determine whether a key exists in your map
deal with edge case r=1 correctly (as mentioned by #trincot in the comments)
deal with edge case arr=[] correctly (the reduce doesn't work without an initial value)
To further improve the speed of your code, do some benchmarking. Apart from switching to a Map, try changing the forEach call to a for … of or for(let i=0; i<….length; i++) loop, and don't keep the individual counts in a temporary arrSum array but just directly sum them (count += sum). Run the benchmarks with inputs of different sizes and different triplet distributions.

Split array into arrays of numbers where the sum is equal to a specific target

I need to create a function that take as parameter an array and a target. It should return an array of arrays where the sum of these numbers equals to the target
sumPairs(array, target) {
}
For example:
sumPairs([1, 2, 3, 4, 5], 7) // output : [[2, 5], [3, 4]]
I know I have to use map(), and probably reduce(), set(), or filter() maybe (I read their documentation in MDN but still cant find out). I tried some ways but I can't get it.
If you guys could help me to find out how to dynamically create arrays and push them into a new array..
I read there some solutions (Split array into arrays of matching values) but I hate to just use created functions without knowing what they really do or how they work.
Some very basic code for achieving it, Just run all over combinations and conditionally add the items you want.
function sumPairs(array, target) {
var res = [];
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array.length; j++){
if(i!=j && array[i]+array[j]==target &&
res.filter((x)=> x[0] == array[j] && x[1] == array[i]).length == 0 )
res.push([array[i], array[j]]);
}
}
return res;
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
Option 2 - see this answer for more options (like using reduce)
function sumPairs(array, target) {
return array.flatMap(
(v, i) => array.slice(i+1).filter(w => (v!=w && v+w==target)).map(w=> [w,v])
);
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
"The exercise says that it sould be arrays of pairs that sum the
target value so I think only 2 items"
If you need a pair that matches a sum and you pick any number from the list, you are left with
the following equation to solve num + x = sum where we want to find x. E.g. if you picked 7 and the target sum is 10 then you know you are looking for a 3.
Therefore, we can first construct a counting map of the numbers available in our list linear (O(n)) time and then search for matches in linear time as well rather than brute forcing with a quadratic algorithm.
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
return nums.reduce((pairs, num) => {
countByNum[num]--;
const target = sum - num;
if (countByNum[target] > 0) {
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[num]++;
}
return pairs;
}, []);
}
function countGroupByNum(nums) {
return nums.reduce((acc, n) => (acc[n] = (acc[n] || 0) + 1, acc), {});
}
Here's another implementation with more standard paradigms (e.g. no reduce):
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
const pairs = [];
for (const num of nums) {
const target = sum - num; //Calculate the target to make the sum
countByNum[num]--; //Make sure we dont pick the same num instance
if (countByNum[target] > 0) { //If we found the target
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[target]++; //Didin't find a match, return the deducted num
}
}
return pairs;
}
function countGroupByNum(nums) {
const countByNum = {};
for (const num of nums) {
countByNum[num] = (countByNum[num] || 0) + 1;
}
return countByNum;
}
You can also sort your array and find all the pairs with given sum by using two pointer method. Place the first pointer to the start of the array and the second pointer to the end.
if the sum of the values at the two places is :
More than target: Decrement your second pointer by 1
Less than target: Increment your first pointer by 1
Equal to target: This is one possible answer, push them to your answer array and increment your first pointer by 1 and decrement your second pointer by 1.
This is more performant solution with complexity O(n*log(n))

JavaScript split array into dynamical number of arrays

Is there a nice ES6 way of splitting an array into an array of arrays with each element in source array going into the next target array and repeating across all of the source array?
For example
source = [1,2,3,4,5,6,7,8,9,10,11,12,13]
if target arrays were 2 I would like to get output
output = [
[1,3,5,7,9,11,13],
[2,4,6,8,10,12]
]
if target arrays were 3 I would like to get output
output = [
[1,4,7,10,13],
[2,5,8,11],
[3,6,9,12]
]
Using reduce, it can be done. Here's the solution for a size of target array:
[1,2,3,4,5,6,7,8,9,10,11,12,13].reduce(function (acc, curr, idx) {
acc[idx % size] ? acc[idx % size].push(curr) : acc[idx % size] = [curr];
return acc
}, []);
You can do something like this
Get the divisor and remainder
create a array of length n, with values `divisor + 1 ( for first remainder number of elements ) OR 0 ( we use this to equally distribute the extra elements to the initial elements )
Loop over the array we created above and slice the array and add to final array
let source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
let divideInParts = (arr, number) => {
let divisor = Math.floor(arr.length / number)
let remainder = arr.length % number
let tempArr = Array.from({length: number}, (_,i)=> divisor +( remainder-- > 0 ))
let start = 0
let final = tempArr.map((v,i)=>{
let val = i === 0 ? arr.slice(0, v) : arr.slice(start, start + v)
start += v
return val
})
return final
}
console.log(divideInParts(source, 2))
console.log(divideInParts(source, 3))
console.log(divideInParts(source, 13))
console.log(divideInParts(source, 10))

For Loop that calculates sum of squred numbers in array

I am working on a challenge and in need of some help:
Write a for loop that calculates sum of squares of items in an array of numbers. Example: For array [ 1, 2, 3, 4 ] it calculates the sum of squares as 30 (i.e. 1 + 4 + 9 + 16). I have a fiddle set up if anyone wants to have a closer look. Thanks for your help!
https://jsfiddle.net/jamie_shearman/2drt56e3/23/
var aFewNumbers = [ 1, 2, 3, 7 ];
var squareOfAFewNumbers = 0;
for( var i = 0; i <= aFewNumbers; i++ ) {
squareOfAFewNumbers = squareOfAFewNumbers * aFewNumbers[i] ;
}
console.log( squareOfAFewNumbers );
Your math is wrong. As an obvious issue, the variable starts at 0 and then is multiplied by each array element; 0 times anything is 0, so it will always remain 0 no matter what the values are. Not to mention your loop isn't looking at the length of the array as a stopping condition, which it should be, since you want to iterate from the beginning to the end of the array.
You need to iterate through to the array's length, square each array element, and add that square to the variable:
for( var i = 0; i < aFewNumbers.length; i++ ) {
squareOfAFewNumbers += aFewNumbers[i] * aFewNumbers[i];
}
If you can use ES6, you can even use higher-order array functions to simplify this more:
var squareOfAFewNumbers = aFewNumbers.reduce((result, entry) => result + entry * entry, 0);
There are multiple approaches you can take for reaching the desired result, but as you've mentioned that you must write a for loop; therefore, I sorted the answers by having that in mind.
Using the for loop
let numbers = [1, 2, 3, 7],
sum = 0;
for(let i = 0; i < numbers.length; i++) {
sum += Math.pow(numbers[i], 2)
}
// Sum is now 63
Using forEach method of the array object
let numbers = [1, 2, 3, 7],
sum = 0;
numbers.forEach(number => sum += Math.pow(number, 2))
// Sum is now 63
Oneliner
let sum = [1, 2, 3, 7].reduce((a, c) => a + Math.pow(c, 2))
The reduce method uses an accumulator to store temporary results, the accumulator is passed to the callback as the first argument and the second argument is the element's value, you can read more about the reduce method here.
You can use JavaScript pow() Method to create the square and sum it to the sumSquareOfAFewNumbers.
var aFewNumbers = [ 1, 2, 3, 7 ];
var sumSquareOfAFewNumbers = 0;
aFewNumbers.forEach(function(element) {
sumSquareOfAFewNumbers += Math.pow(element, 2);
});
console.log(sumSquareOfAFewNumbers)

Factorialise all numbers in array with .map

I have an array of numbers e.g. [2, 4, 5] and must get the factorials in a new array. E.g. [2, 24, 120]
I am using .map as you can see to perform the function on each integer in the array however, this does not work? I assume something is wrong with the recursive function?
Thanks.
function getFactorials(nums) {
if(nums > 1){
factarr = nums.map(x => x * (nums - 1));
}
return factarr;
}
You could take a function for the factorial and map the values.
The function has a recusive style with a check for the value. if the value is zero, then the function exits with one. Otherwise it returnd the product of the actual value and the result of the call of the function with decremented value.
The check uses an implict casting of a falsy to a boolean value for the conditional (ternary) operator ?:.
const fact = n => n ? n * fact(n - 1) : 1;
var array = [2, 4, 5],
result = array.map(fact);
console.log(result);
Just create a function that calculates the factorial of a given number then just use it as the callback for the map function.
As the main part is the way to calculate the factoriel, here's two manners to do that task
Factoriel function iterative way :
const fact = n => {
let f = 1,
i = n;
for(; i > 1; i--) f *= i;
return f;
};
console.log(fact(4)); /** outpuut: 24 **/
Factoriel function recursive way :
const fact = n => n > 1 ? n * fact(n - 1) : n;
console.log(fact(4)); /** outpuut: 24 **/
And the final code :
const arr = [2, 4, 5],
fact = n => n > 1 ? n * fact(n - 1) : n,
factArr = arr.map(i => fact(i));
console.log(factArr); /** output: [2, 24, 120] **/
You are doing the recursion wrong, my approach would be to define the factorial calculator as a separate function:
function getFactorials(nums) {
function factorial(n){
return n === 0 ? 1 : n * factorial(n - 1);
}
return nums.map(x => factorial(x));
}
console.log(getFactorials([0, 1, 2, 3, 4, 5 ,6]));
You need to calculate each factorial in array, your current code is not doing that. Consider following example:
function factorial(num) {
if (num === 0 || num === 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
const facts = [2, 4, 5];
const factsArr = facts.map(num => factorial(num));
In you code you was just multiplying each member of array by array itself.
Instead of doing it recursively, I took the solution from #Amin Jafari which uses reduce(). This function is quicker than the recursive solution.
First we generate an array. We do so by using Array(n + 1). n is the factorial so e.g. for 6! our n would be 6. We get the indices with keys() but Array() by itself only returns a truly empty array and keys() only returns an iterator. So we spread it and put the result of that into a new array. Thus, we have e.g. [0,1,2,3,4,5,6] (for n + 1 with n = 6). We exclude the 0 with slice(1).
Afterwards we finally apply reduce. Reduce iterates over all elements, applies a function while keeping track of an accumulator. Our accumulator here is the current product. So what happens is that 1 * 2 gets calculated and the result saved in a, our accumulator. Then we multiply a with the next value, so 2 * 2* and this happens until we went through our whole self generated array.
This function based on reduce we can then use to transform each value in our original array with map().
const factorial = n => [...Array(n+1).keys()].slice(1).reduce((a,c) => a * c),
data = [2, 4, 5];
let res = data.map(v => factorial(v));
console.log(res);
I know that this post has a lot of answers already, but I might have something to add:
If you are planning to use the recursive function a lot to calculate factorials, let's say you need this in a browser game every .5 secs, you will notice that it is consuming a lot of resources, mainly your time 😉.
My proposition is:
calculate the factorials once
store them in the app state
look them up instead of calculating them
example code (based on Nina Scholz's anwer):
// create this earlier, put it in the application state
const state = {lookupFact: []}
const fact = n => n ? n * fact(n - 1) : 1;
// only calculate the factorials once
function lookupFact(par) {
if (state.lookupFact.length == 0) {
for (var i = 0; i <= 170; i++) {
state.lookupFact[i] = fact(i)
}
}
return state.lookupFact[par]
}
// use it like this later on
console.log(lookupFact(1), lookupFact(10), lookupFact(5))
As I said, you should use this only if you have to calculate factorials all the time.
var arr = [2,3,4,5,6,7]
arr.map((value, ind) => {
var facts = 1;
for (value ;value > 0 ;value--) {
facts = facts *value;
}
console.log(facts);
})

Categories

Resources