Related
Given a JavaScript function that takes in an array of numbers as the first and the only argument.
The function then removes one element from the array, upon removal, the sum of elements at odd indices is equal to the sum of elements at even indices. The function should count all the possible unique ways in which we can remove one element at a time to achieve balance between odd sum and even sum.
Example var arr = [2, 6, 4, 2];
Then the output should be 2 because, there are two elements 6 and 2 at indices 1 and 3 respectively that makes the combinations table.
When we remove 6 from the array
[2, 4, 2] the sum at odd indexes = sum at even indexes = 4
if we remove 2
[2, 6, 4] the sum at odd indices = sum at even indices = 6
The code below works perfectly. There might be other solutions but I want to understand this one, because I feel there is a concept I have to learn here. Can someone explain the logic of this algorithm please?
const arr = [2, 6, 4, 2];
const check = (arr = []) => {
var oddTotal = 0;
var evenTotal = 0;
var result = 0;
const arraySum = []
for (var i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
evenTotal += arr[i];
arraySum[i] = evenTotal
}
else {
oddTotal += arr[i];
arraySum[i] = oddTotal
}
}
for (var i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
if (arraySum[i]*2 - arr[i] + oddTotal === (arraySum[i - 1] || 0)*2 + evenTotal) {
result = result +1
};
} else if (arraySum[i]*2 - arr[i] + evenTotal === (arraySum[i - 1] || 0)*2 + oddTotal) {
result = result +1
}
}
return result;
};
I am trying to solve this.
Nominal Case:
For the array[1,2,3,5,2,4,7,54], and the number 6. The sequences[1,2,3] and [4,2] will be removed because the add up to 6. function will return [5,7,54]. If two sequences overlap, remove the first sequence.
Overlapping Case:
For the array [1,2,3,9,4,1,4,6,7] and the number 5, the sequence [2,3,] and [4,1] are removed because they add up to 5. For the [4,1] case. you see that [4,1,4] represents two overlapping sequences. because [4,1] adds up to 5 first is removed and the 4 is not removed even through [1,4] adds up to 5. We say that [4,1] and [1,4] overlap to give [4,1,4] and in those cases the first of the overlapping sequences is removed . functin will return [1,9,4,6,7]
function consecutive(arr, len, num) {
var newarr = [];
for (let i = 1; i < len; i++) {
var sum = arr[i] + arr[i + 1];
if (sum == num) {
newarr.push(arr[i]);
newarr.push(arr[i + 1]);
}
}
return newarr;
}
let arr = [1, 2, 3, 5, 2, 4, 7, 54];
let len = arr.length;
let num = 6;
console.log(consecutive(arr, len, num));
Get Wrong Output
[2,4]
You could store the target index of wrong items and if no one to filter out check the next elements if they sum up to the wanted value.
function consecutive(array, num) {
return array.filter(
(wrong => (v, i, a) => {
if (i <= wrong) return false;
let sum = 0, j = i;
while (j < a.length) {
if ((sum += a[j]) === num) {
wrong = j;
return false;
}
j++;
}
return true;
})
(-1)
);
}
console.log(consecutive([1, 2, 3, 5, 2, 4, 7, 54], 6));
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));
I have an array e.g.
var arr = [2,7,3,8,9,4,9,2,8,7,9,7,3,2,4,5,7,8,2,7,6,1,8];
I want that (I think for-loop is best for this to loop over this) a for-loop loops over the whole array and gets 5 items near eachother in the array and runs a function with those 5 items to calculate an average of them. This has of course to repeat till there are no parts of 5 available. The array above has 23 values. So when I should run a code on it, it can loop 4 times on it, cos one more time can't cos it has 3/5 values.
I thought about doing:
for (var i = 0; i < arr.length; i++) {
doThisFunction(i, i+1, i+2, i+3, i+4 );
}
but that shouldn't be efficient I believe... any help?
You're on to something, the easy way to do it is
var arr = [2,7,3,8,9,4,9,2,8,7,9,7,3,2,4,5,7,8,2,7,6,1,8];
var result = [];
for (var i=0; (i+5)<arr.length; i=i+5) {
var average = (arr[i] + arr[i+1] + arr[i+2] + arr[i+3] + arr[i+4]) / 5;
result.push(average);
}
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) + '</pre>';
The somewhat fancier way to do the same thing
var result = arr.map(function(x,i) {
return i%5===0 ? arr.slice(i, i+5).reduce(function(a,b) {return a+b}) / 5 : NaN;
}).filter(isFinite);
Use array.slice:
for (var i = 0; i < Math.floor(arr.length/5); i++) {
f(arr.slice(i*5, i*5+5))
}
The following uses reduce and a slice to sum up a range of values from the array.
function averageRange(arr, start, end) {
return (function(range) {
return range.reduce(
function(total, val) {
return total + val;
}, 0) / range.length;
}([].slice.apply(arr, [].slice.call(arguments, 1))))
}
function averageEveryN(arr, n) {
return arr.map(function(_, index, arr) {
return index % n === 0 ? averageRange(arr, index, index + count) : NaN;
}).filter(isFinite).slice(0, Math.floor(arr.length / n));
}
function println(text) {
document.getElementsByTagName('body')[0].innerHTML += text + '<br />';
}
var arr = [2, 7, 3, 8, 9, 4, 9, 2, 8, 7, 9, 7, 3, 2, 4, 5, 7, 8, 2, 7, 6, 1, 8];
var count = 5;
averageEveryN(arr, count).map(function(value, index) {
println((index + 1) + '.) ' + value.toFixed(4));
});
Output
1.) 5.8000
2.) 6.0000
3.) 5.0000
4.) 5.8000
There is an array of numbers [1,2,3,4,5,6,7,8,9,10]
I need to get all numbers from this sequence that are different from current for more than 2 items, but looped.
For example if current number is one, so new list should have everything except 9,10,1,2,3, or if current number is four so new list should be everything except 2,3,4,5,6.
Is there any technique how to make this, without creating multiple loops for items at start and at the end?
Thank you.
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var exclude = function (start, distance, array) {
var result = [];
for (var i = 0; i < array.length; i++) {
var d = Math.min(
Math.abs(start - i - 1),
Math.abs(array.length + start - i - 1)
)
if (d > distance) {
result.push(array[i]);
}
}
return result;
}
I think this performs what you asked:
// Sorry about the name
function strangePick(value, array) {
var n = array.length
, i = array.indexOf(value);
if (i >= 0) {
// Picked number
var result = [value];
// Previous 2 numbers
result.unshift(array[(i + n - 1) % n]);
result.unshift(array[(i + n - 2) % n]);
// Next 2 numbers
result.push(array[(i + 1) % n]);
result.push(array[(i + 2) % n]);
return result;
} else {
return [];
}
}
Some tests:
var array = [1,2,3,4,5,6,7,8,9,10];
console.log(strangePick(1, array)); // [9,10,1,2,3]
console.log(strangePick(4, array)); // [2,3,4,5,6]
You may use javascript array.slice:
function get_offset_sequence(arr, index, offset) {
var result = [];
if (index - offset < 0) {
result = arr.slice(index - offset).concat(arr.slice(0, index + offset + 1));
}
else if (index + offset > arr.length - 1) {
result = arr.slice(index - offset).concat(arr.slice(0, Math.abs(arr.length - 1 - index - offset)));
}
else {
result = arr.slice(index - offset, index + offset + 1)
}
return result;
}
Example of use:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var index = 1;
var offset = 2;
for (var i=0; i < 10; i++) { console.log(i, arr[i], get_offset_sequence(arr, i, offset)) }