Array list get sum of the alternate result - javascript

Is there a function how can I easily get the sum of alternating result:
Here is my simple raw list:
let x = [1, 2 , 3 , 4 , 5 , 6 ,7];
expected result:
sum by first: 1 + 3 + 5 + 7 = 16
sum by second: 2 + 4 + 6 = 12
sum by third: 3 + 6 = 9
just want to get the sum by alternating index, any suggetsions/comments TIA

You could do this:
let x = [1, 2 , 3 , 4 , 5 , 6 ,7];
function sumBy(firstelem){
var i = firstelem -1,
sum =0;
for(let k=i; k<x.length; k=k+2){
sum = sum + x[k];
}
return sum;
}
console.log(sumBy(1));
console.log(sumBy(2));
console.log(sumBy(3));

You can create your own custom function for these as follows:
const myList = [1, 2, 3, 4, 5, 6, 7];
let skipTake = (take, list) => {
let filtered = list.filter((a, i) => {
if (take == 1) {
return i % 2 == 0;
} else if (take == 2) {
return i != 0 && i % take == 1;
} else {
return i != 0 && (i + 1) % take == 0;
}
});
return filtered.reduce((agg, cur) => agg += cur);
}
console.log("first", skipTake(1, myList))
console.log("second", skipTake(2, myList))
console.log("third", skipTake(3, myList))
console.log("fourth", skipTake(4, myList))

A simple for loop will do the trick
The index inside the loop starts from 1 and goes till length-1 because of your specific requirements.
let x = [1, 2, 3, 4, 5, 6, 7];
const index = 3; //for example
let sum = 0;
for (let i = 1; i < x.length + 1; i++)
sum += (i % index == 0) ? x[i - 1] : 0;
console.log(sum);

Filter and reduce.
Change the if statement to change which indexes are selected. This one will select all even numbered indexes.
let x = [1, 2 , 3 , 4 , 5 , 6 ,7];
let y = x.filter((element, index) => {
if (index % 2 == 0) {
return element;
}
}).reduce((a, b) => a + b);

Related

Finding the first pair that sums to a given integer

function sumPairs(ints, s) {
let result = [];
for(let i = 0; i < ints.length; i++){
for(let j = 0; j < ints.slice(i); j++){
(ints[i] + ints[j] === s && result.length === 0) ? result.push(ints[i], ints[j]) : 0;
}
} return result;
}
sumPairs([1, 2, 3, 4, 5, 6], 10) //returns [6, 4] instead of [4,6]?
How do I fix this so that the function returns the first pair that add up to s, the second argument? I added the result.length === 0 condition in the if statement a further update would be prevented?
Just iterate over the array using for..of loop and use Set to achieve the desired result.
function sumPairs(ints, s) {
const dict = new Set();
for (let num of ints) {
if (dict.has(s - num)) return [s - num, num];
else dict.add(num);
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
Iterations:
Iteration 1 :=> num = 1 and dict is empty
dict doesn't have 9 (because of s - num i.e 10 - 1) so add num i.e 1 to dict.
Iteration 2 :=> num = 2 and dict has 1
dict doesn't have 8 (because of s - num i.e 10 - 2) so add num i.e 2 to dict
Iteration 3 :=> num = 3 and dict has 1, 2
dict doesn't have 7 (because of s - num i.e 10 - 3) so add num i.e 3 to dict
Iteration 4 :=> num = 4 and dict has 1, 2, 3
dict doesn't have 6 (because of s - num i.e 10 - 4) so add num i.e 4 to dict
Iteration 5 :=> num = 5 and dict has 1, 2, 3, 4
dict doesn't have 5 (because of s - num i.e 10 - 5) so add num i.e 5 to dict
Iteration 6 :=> num = 6 and dict has 1, 2, 3, 4, 5
dict have 4 (because of s - num i.e 10 - 6) so return [s - num, num] i.e [4, 6]
I think you might be overcomplicating things a little. There's no need to slice() or to push(), and there's no need to keep on looping after a result has been found:
function sumPairs(ints, s) {
for (let i = 0; i < ints.length; i++) {
for (let j = i; j < ints.length; j++) {
if (ints[i] + ints[j] == s) {
return [ints[i], ints[j]];
}
}
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
As #robby-cornelissen said there's no need to slice. And there's no need for push too as you can return the result simply.
When you do ints.slice(i) you get an array from that position.
You are comparing an int within an array in the second loop.
It didn't enter the second loop until "i === 5" which is in the ints array a [6]. Notice it didn't enter the second until you get an array of one element. Keep in mind 6 == [6] and 1<[6] and 2<[6] etc
Then it goes incrementing the value of j until you get the position of j that gets the value of ints which, summed by the value of the position i results on s.
const twoSum = (arr, target) => {
arr.sort((a, b) => a - b);
//double pointer -> increment, decrement accordingly
let leftPointer = 0;
let rightPointer = arr.length - 1;
while (leftPointer < rightPointer) {
if (arr[leftPointer] + arr[rightPointer] === target) {
return [arr[leftPointer], arr[rightPointer]];
}
if (arr[leftPointer] + arr[rightPointer] > target) {
rightPointer--;
}
if (arr[leftPointer] + arr[rightPointer] < target) {
leftPointer++;
}
}
};
console.log(twoSum([1, 2, 3, 4, 5, 6], 10));

Sum and Difference between odds and evens

So I manage to separate the odd and even numbers but I'm having trouble figuring out how to add the odds with odds and even with evens and then subtract that to get the answer. i.e
(1 + 3 + 5 + 7 + 9) - (2 + 4 + 6 + 8) = 5
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
sumDiff(numbers);
function sumDiff(numbers) {
let even = [];
let odd = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
} // end
else {
odd.push(numbers[i]);
}// end else
} //end of for loop
console.log(odd);
console.log(even);
} // end of function
Now I don't want the full answer, but a nudge in the right direction. I figured I can separate the odd and even numbers first and then go from there.
Would I have to create a new function or could I still get it done within the same function?
Your code works just fine, for the missing functionality you're looking for, you could use the Array.prototype.reduce() function to sum the values of the two arrays you created, like this:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
sumDiff(numbers);
function sumDiff(numbers) {
let even = [];
let odd = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
} // end
else {
odd.push(numbers[i]);
}// end else
} //end of for loop
console.log(odd);
console.log(even);
let oddSum = odd.reduce((r, s) => r += s, 0)
let oddEven = even.reduce((r, s) => r += s, 0)
console.log("odd sum total: " + oddSum)
console.log("even sum total: " + oddEven)
console.log("difference: " + (oddSum - oddEven))
} // end of function

Array of numbers to batches of given sum

I've a JavaScript array and sum as input
array = [4,8,2,4,2,2,8,12,4,2, 2]
sum = 12 // all the time sum will be 12
I want 2d array, the numbers in batches should be sum equals or less than 12
The output array should look like
[
[4,8],
[2,4,2,2,2],
[8, 4],
[12],
[2]
]
4 + 8 = 12
2 + 4 + 2 + 2 + 2 = 12
...
2 is left at the end
Other examples
1) array = [6,5,3,3,3,2,2,2,2]
sum = 12
output: [ [6,3,3], [5,3,2,2], [2,2] ]
One the number is allotted to subset, it should not used to other subset
remaining numbers can be added to the last but sum should be less than 12, else add one more array and add remaining ones
The input array can have any integer from 1 - 12
How can I get the output I want?
Try this function. I commented the code as much as possible to clarify it.
const example1 = [4, 8, 2, 4, 2, 2, 8, 12, 4, 2, 2];
const example2 = [6, 5, 3, 3, 3, 2, 2, 2, 2];
const example3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const example4 = [5,12,3,4,4,1,1,1,5,8,12,6,9,11,6];
const example5 = [4, 2, 1, 2, 3, 3, 5, 7, 8, 9];
const lookAhead = function(array, searchFor) {
return array.some(val => {
return val <= searchFor;
});
}
function findPairs(inputArray) {
// First sort array in descending order
inputArray.sort((a, b) => b - a);
console.log("input", JSON.stringify(inputArray.slice(0)));
// set variables
const pairArray = [];
const max = 12;
inputArray.forEach(function(num, index) {
// when looping the array we will replace values with null once completed,
// Therefore if value is null no need to go futher
if (num == null)
return;
// initiate pair value with current number
const pair = [num];
// set it to null in input array
inputArray[index] = null;
// if number equals to max (ie. 12) no need to go futher
if (num == max) {
pairArray.push(pair);
return;
}
let total = num;
// Loop through array again to see matching numbers
for (let i = 0; i < inputArray.length; i++) {
// Don't go futher if it is a null value
if (inputArray[i] == null)
continue;
const add = total + inputArray[i];
/* if the total is less than max (12) then we check if we have an edge case
* For example in an array like [6, 5, 3, 3, 3], 6 + 5 is 11 but in next loops we
* will not find any "1" to get to 12. Therefore we escape this iteration and check
* next numbers. In this case the result would be 6 + 3 + 3
*/
if (add < max) {
const found = lookAhead(inputArray.slice(i), max - add);
if (found) {
pair.push(inputArray[i]);
total = add;
inputArray[i] = null;
}
} else if (add == max) {
// The addition is equals to max. Push the number and set it to null in input array
pair.push(inputArray[i]);
inputArray[i] = null;
total = 0;
break;
}
}
// Push pair array from this iteration to pairArray
pairArray.push(pair);
});
console.log("output", JSON.stringify(pairArray));
console.log("-------");
}
findPairs(example1);
findPairs(example2);
findPairs(example3);
findPairs(example4);
findPairs(example5);
A little complex to understand but here you go...
let originalArray = [7, 7, 7, 7, 7]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([]);
originalArray.forEach(element => {
for (let i = 0; i < twoDiArray.length; i++) {
if (CalculateSum(twoDiArray[i], element) <= 12) {
twoDiArray[i].push(element);
break;
} else {
if (twoDiArray.length - 1 === i) {
twoDiArray.push([element]);
break;
}
}
}
})
console.log(twoDiArray)
Here you... I will keep both answers open for future use of others...
let originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([originalArray[0]]);
originalArray.splice(0, 1);
do {
originalArray.forEach((element, index) => {
for (let i = 0; i < twoDiArray.length; i++) {
let summ = CalculateSum(twoDiArray[i], element);
if (summ === 12) {
twoDiArray[i].push(element);
originalArray.splice(index, 1);
break;
} else {
if (index === originalArray.length - 1) {
if (CalculateSum(twoDiArray[twoDiArray.length - 1], originalArray[0]) <= 12) {
twoDiArray[twoDiArray.length - 1].push(originalArray[0]);
break;
} else {
twoDiArray.push([originalArray[0]]);
}
originalArray.splice(0, 1);
}
}
}
})
}
while (originalArray.length > 0);
console.log(twoDiArray)

Trying to Use Recursion to solve Fibonacci (javascript)

This is the question:
Given a positive integer num, return the sum of all odd Fibonacci numbers that are less than or equal to num.
The first two numbers in the Fibonacci sequence are 1 and 1. Every additional number in the sequence is the sum of the two previous numbers. The first six numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8.
For example, sumFibs(10) should return 10 because all odd Fibonacci numbers less than or equal to 10 are 1, 1, 3, and 5.
This is what I tried
function sumFibs(num, total = [1, 1], n = (total.length - 1 + total.length - 2)) {
if(n == num){
return total;
}
total.push(n);
sumFibs(num, n = (total.length - 1 + total.length - 2), total);
};
Question
Is it possible to use my method to make this work, if so how do I fix the syntax? If not, how would you solve the problem.
Many thanks!
continuation passing style
Continuation passing style effectively gives you programmatic return. Using a CPS function recursively can make program complexity evaporate into thin air -
const identity = x =>
x
const sumfib = (n = 0, then = identity) =>
n <= 0
? then(0, 1, 1) // base case
: sumfib // inductive: solve smaller subproblem
( n - 1
, (sum, fib, temp) =>
then(sum + fib, temp, fib + temp)
)
console.log
( sumfib(0) // 0 = 0
, sumfib(1) // 1 = 0 + 1
, sumfib(2) // 2 = 0 + 1 + 1
, sumfib(3) // 4 = 0 + 1 + 1 + 2
, sumfib(4) // 7 = 0 + 1 + 1 + 2 + 3
, sumfib(5) // 12 = 0 + 1 + 1 + 2 + 3 + 5
, sumfib(6) // 20 = 0 + 1 + 1 + 2 + 3 + 5 + 8
, sumfib(7) // 33 = 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13
)
loop/recur
loop and recur give us the ability to write recursive programs like the one above, but will not encounter a stack overflow error -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let r = f()
while (r && r.recur === recur)
r = f(...r.values)
return r
}
const sumfib = (n = 0) =>
loop // <-- loop with vars
( ( m = n
, sum = 0
, fib = 1
, temp = 1
) =>
m <= 0 // <-- exit condition
? sum // <-- base case
: recur // <-- recur with updated vars
( m - 1
, sum + fib
, temp
, temp + fib
)
)
console.log
( sumfib(0) // 0 = 0
, sumfib(1) // 1 = 0 + 1
, sumfib(2) // 2 = 0 + 1 + 1
, sumfib(3) // 4 = 0 + 1 + 1 + 2
, sumfib(4) // 7 = 0 + 1 + 1 + 2 + 3
, sumfib(5) // 12 = 0 + 1 + 1 + 2 + 3 + 5
, sumfib(6) // 20 = 0 + 1 + 1 + 2 + 3 + 5 + 8
, sumfib(7) // 33 = 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13
)
streamz
so-called streams are interesting because they can possibly generate infinite values, but we don't have to compute them all at once. Again we can define our program in simple terms and let useful primitives do all of the hard work -
const fibs =
stream(0, _ =>
stream(1, _ =>
streamAdd(fibs, fibs.next)))
console.log(streamTake(fibs, 10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
console.log(streamTake(streamSum(fibs), 10))
// [ 0, 1, 2, 4, 7, 12, 20, 33, 54, 88 ]
We just implement stream, streamAdd, streamSum, and streamTake -
const emptyStream =
Symbol('emptyStream')
const stream = (value, next) =>
( { value
, get next ()
{ delete this.next
return this.next = next()
}
}
)
const streamAdd = (s1, s2) =>
s1 === emptyStream || s2 === emptyStream
? emptyStream
: stream
( s1.value + s2.value
, _ => streamAdd(s1.next, s2.next)
)
const streamSum = (s, sum = 0) =>
s === emptyStream
? emptyStream
: stream
( sum + s.value
, _ => streamSum(s.next, sum + s.value)
)
const streamTake = (s = emptyStream, n = 0) =>
s === emptyStream || n <= 0
? []
: [ s.value, ...streamTake(s.next, n - 1) ]
Expand the snippet below to verify the results in your own browser -
const emptyStream =
Symbol('emptyStream')
const stream = (value, next) =>
( { value
, get next ()
{ delete this.next
return this.next = next()
}
}
)
const streamAdd = (s1, s2) =>
s1 === emptyStream || s2 === emptyStream
? emptyStream
: stream
( s1.value + s2.value
, _ => streamAdd(s1.next, s2.next)
)
const streamSum = (s, sum = 0) =>
s === emptyStream
? emptyStream
: stream
( sum + s.value
, _ => streamSum(s.next, sum + s.value)
)
const streamTake = (s = emptyStream, n = 0) =>
s === emptyStream || n <= 0
? []
: [ s.value, ...streamTake(s.next, n - 1) ]
const fibs =
stream(0, _ =>
stream(1, _ =>
streamAdd(fibs, fibs.next)))
console.log(streamTake(fibs, 10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
console.log(streamTake(streamSum(fibs), 10))
// [ 0, 1, 2, 4, 7, 12, 20, 33, 54, 88 ]
Four things
(1) You don't return the result of the recursive call, therefore it does never get passed up to the caller:
sumFibs(4, [1, 1]) -> sumFibs(4, [1, 1, 2]) -> sumFibs(4, [1, 1, 2, 3])
<- [1, 1, 2, 3]
// v the return you do
// v the return you need too
(2) In the recursive call, the order of arguments is wrong.
(3) I guess instead of taking the arrays length minus 1, you want to access the property at that position in the total array.
(4) Why do you actually n as an argument? As it is only depending on total, it could also just be a variable:
function sumFibs(num, total = [1, 1]) {
const n = total[total.length - 1] + total[total.length - 2];
if(n > num){
return total;
}
total.push(n);
return sumFibs(num, total);
}
console.log(sumFibs(19));
This can be solved without an array accumulator; use n as a counter and curr and prev vars to store the data necessary to compute the Fibonacci series. Whenever we have an odd curr, add it to the running total and pass it up the call stack.
const sumOddFibs = (n, curr=1, prev=0) => {
if (curr < n) {
return sumOddFibs(n, curr + prev, curr) + (curr % 2 ? curr : 0);
}
return 0;
};
console.log(sumOddFibs(10));
As an aside, recursion is a pretty poor tool for just about anything that involves a sequential 0..n counter. Iteration makes more sense: less overhead, easier to understand and no risk of blowing the call stack. I'd also separate computation of the Fibonacci series (which is a good use case for a generator) from filtering oddness and summing so that each step is independent and can be reused:
const sum = arr => arr.reduce((a, e) => a + e);
const odds = arr => arr.filter(e => e % 2);
function *fibsBelow(n) {
for (let prev = 0, curr = 1; curr < n;) {
yield curr;
const tmp = curr;
curr += prev;
prev = tmp;
}
}
console.log(sum(odds([...fibsBelow(10)])));

Finding closest sum of numbers to a given number

Say I have a list [1,2,3,4,5,6,7]
and I would like to find the closest sum of numbers to a given number. Sorry for the crappy explanation but here's an example:
Say I have a list [1,2,3,4,5,6,7] I want to find the closest numbers to, say, 10.
Then the method should return 6 and 4 or 7 and 3 because its the closest he can get to 10. So 5 + 4 would be wrong because thats 9 and he can make a 10.
another example : you want the closest to 14 , so then he should return 7 and 6
If you got any questions plz ask because its difficult to explain what I want :P
Functions for combine, locationOf, are taken from different answers, written by different authors.
printClosest([0.5,2,4] , 5);
printClosest([1, 2, 3, 4, 5, 6, 7], 28);
printClosest([1, 2, 3, 4, 5, 6, 7], 10.9);
printClosest([1, 2, 3, 4, 5, 6, 7], 10, 2);
printClosest([1, 2, 3, 4, 5, 6, 7], 10, 3);
printClosest([1, 2, 3, 4, 5, 6, 7], 14, 2);
function printClosest(array, value, limit) {
var checkLength = function(array) {
return array.length === limit;
};
var combinations = combine(array); //get all combinations
combinations = limit ? combinations.filter(checkLength) : combinations;//limit length if required
var sum = combinations.map(function(c) { //create an array with sum of combinations
return c.reduce(function(p, c) {
return p + c;
}, 0)
});
var sumSorted = sum.slice(0).sort(function(a, b) {//sort sum array
return a - b;
});
index = locationOf(value, sumSorted);//find where the value fits in
//index = (Math.abs(value - sum[index]) <= Math.abs(value - sum[index + 1])) ? index : index + 1;
index = index >= sum.length ? sum.length - 1 : index;
index = sum.indexOf(sumSorted[index]);//get the respective combination
console.log(sum, combinations, index);
document.getElementById("result").innerHTML += "value : " + value + " combi: " + combinations[index].toString() + " (limit : " + (limit || "none") + ")<br>";
}
function combine(a) {
var fn = function(n, src, got, all) {
if (n == 0) {
if (got.length > 0) {
all[all.length] = got;
}
return;
}
for (var j = 0; j < src.length; j++) {
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
}
return;
}
var all = [];
for (var i = 0; i < a.length; i++) {
fn(i, a, [], all);
}
all.push(a);
return all;
}
function locationOf(element, array, start, end) {
start = start || 0;
end = end || array.length;
var pivot = parseInt(start + (end - start) / 2, 10);
if (end - start <= 1 || array[pivot] === element) return pivot;
if (array[pivot] < element) {
return locationOf(element, array, pivot, end);
} else {
return locationOf(element, array, start, pivot);
}
}
<pre id="result"><pre>
var data= [1, 2, 3,4,5,6,7];
var closest = 14;
for (var x = 0; x < data.length; x++) {
for (var y = x+1; y < data.length; y++) {
if(data[x] + data[y] == closet){
alert(data[x].toString() + " " + data[y].toString());
}
}
}
From what I understood from your question, I made this snippet. I assumed you did not wanted to have the same digit twice (e.g 14 => 7 + 7).
It is working with your examples.
var arr = [1, 2, 3, 4, 5, 6, 7];
var a = 0, b = 0;
var nb = 14;
for(var i in arr) {
for(var j in arr) {
if(i != j) {
var tmp = arr[i] + arr[j];
if(tmp <= nb && tmp > a + b) {
a = arr[i];
b = arr[j];
}
}
}
}
document.write("Closest to " + nb + " => " + a + " + " + b);
I have a little bit long winded solution to the problem just so it is easier to see what is done.
The main benefits with solution below:
The second loop will not start from beginning of the array again. What I mean that instead of having loop_boundary for second loop as 0 as you normally would, here it starts from next index. This helps if your numbers array is long. However, if it as short as in example, the impact in performance is minimal. Decreasing first loop's boundary by one will prevent errors from happening.
Works even when the wanted number is 1 or negative numbers.
Fiddle:
JSFiddle
The code:
var numbers = [1,2,3,4,5,6,7];
var wanted_number = 1;
var closest_range, closest1, closest2 = null;
var loop1_boundary = numbers.length-1;
for(var i=0; i<loop1_boundary; i++) {
var start_index = i+1;
var loop2_boundary = numbers.length;
for(var k=start_index; k<loop2_boundary; k++) {
var number1 = parseInt(numbers[i]);
var number2 = parseInt(numbers[k]);
var sum = number1 + number2;
var range = wanted_number - sum;
document.write( number1+' + '+number2 +' < '+closest_range+'<br/>' );
if(Math.abs(range) < Math.abs(closest_range) || closest_range == null ) {
closest_range = range;
closest1 = number1;
closest2 = number2;
}
}
if(range==0){
break;
}
}
document.write( 'closest to given number was '+closest1+' and '+closest2+'. The range from wanted number is '+closest_range );
This proposal generates all possible combinations, collects them in an object which takes the sum as key and filters then the closest sum to the given value.
function getSum(array, sum) {
function add(a, b) { return a + b; }
function c(left, right) {
var s = right.reduce(add, 0);
if (s > sum) {
return;
}
if (!result.length || s === result[0].reduce(add, 0)) {
result.push(right);
} else if (s > result[0].reduce(add, 0)) {
result = [right];
}
left.forEach(function (a, i) {
var x = left.slice();
x.splice(i);
c(left.slice(0, i), [a].concat(right));
});
}
var result = [];
c(array, [], 0);
return result;
}
function print(o) {
document.write('<pre>' + JSON.stringify(o, 0, 4) + '</pre>');
}
print(getSum([1, 2, 3, 4, 5, 6, 7], 10));
print(getSum([1, 2, 3, 4, 5, 6, 7], 14));
print(getSum([1, 2, 3, 4, 5, 6, 7], 19));

Categories