I have the code like below to return the number that makes the sum of each line the same.
let getnums = () => {
var numsarray = [];
var arrays = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var len = arrays.length;
while (len > 0) {
var rans = Math.floor(Math.random() * len);
numsarray.push(arrays[rans]);
arrays.splice(rans, 1);
len = len - 1;
}
return numsarray;
};
let done = false
function test(num){
while (!done) {
let output = getnums();
if (
output[0] + output[1] + output[2] == 15 &&
output[1] + output[4] + output[7] == 15 &&
output[2] + output[5] + output[8] == 15 &&
output[0] + output[3] + output[6] == 15 &&
output[2] + output[4] + output[6] == 15 &&
output[3] + output[4] + output[5] == 15 &&
output[6] + output[7] + output[8] == 15 &&
output[0] + output[4] + output[8] == 15
) {
done = true
console.log(output)
}
}
}
test()
The code works fine, but I am looking for ways to shorten the if statement.
My current code only will work result 3*3 because of the specific if statement , I am looking for a better and that will work for all different sizes:
E.g: 4*4, a function produces:
if(
output[0] + output[1] + output[2] +output[3]
output[4] + output[5] + output[6] +output[7]
....
)
I have already had idea or using loop to make randomnumber, but don't know how to make if statement.
Is it possible I could use loop or other methods to create the if statement?
Any suggestions or ideas?
Thank you!
Since you have perfect square matrices, you can use the below logic:
Every row needs to have same sum.
Every column needs to have same sum.
Both diagonals need to have same sum.
So, we add every element of the matrix twice and add diagonal elements one more time. Needlessly to say that the value at the center of the matrix will be added 4 times. We do get a total sum.
We need to compare this sum with the new desired sum derivation in the following way:
desired_sum * (R + C + 2)
where R is no. of rows, C is no. of columns and 2 is for the 2 diagonals. Since R = C for your case, it will be
desired_sum * (N * 2 + 2)
where N is the no. of rows or columns of the matrix.
Snippet:
var mat = [
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
];
function test(mat, N, desired_sum){
let sum = 0;
let d1_col = 0,d2_col = N - 1;
for(let i = 0; i < N; ++i, d1_col++, d2_col--){
for(let j = 0; j < N; ++j){
sum += 2 * mat[i][j];
if(d1_col == j) sum += mat[i][j];
if(d2_col == j) sum += mat[i][j];
}
}
return sum == desired_sum * (N * 2 + 2);
}
console.log(test(mat, mat.length, 4));
For the 3x3 problem, you could take the following array of indices and check the sum.
For 4x4 arrays, take another array of indices.
const
getSum = indices => indices.reduce((sum, index) => sum + output[index], 0),
indices3 = [[0, 1, 2], [1, 4, 7], [2, 5, 8], [0, 3, 6], [2, 4, 6], [3, 4, 5], [6, 7, 8], [0, 4, 8]];
if (indices3.every(indices => getSum(indices) === 15)) {
// ...
}
Related
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
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)
This question already has answers here:
How to reduce consecutive integers in an array to hyphenated range expressions?
(13 answers)
Closed 2 years ago.
I want to concatenate a sequence of numbers in a readable string. Consecutive numbers should be merged like this '1-4'.
I'm able to concatenate an array with all the numbers into a complete string but I'm having trouble combining / merging consecutive numbers.
I tried comparing the previous and next values with the current one in the loop with several if-conditions but I couldn't seem to find the right ones to make it work properly.
Examples:
if(ar[i-1] === ar[i]-1){}
if(ar[i+1] === ar[i]+1){}
My code looks like this:
var ar = [1,2,3,4,7,8,9,13,16,17];
var pages = ar[0];
var lastValue = ar[0];
for(i=1; i < ar.length; i++){
if(ar[i]-1 === lastValue){
pages = pages + ' - ' + ar[i];
}else{
pages = pages + ', ' + ar[i];
}
}
alert(pages);
Result is: 1 - 2, 3, 4, 7, 8, 9, 13, 16, 17
In the end it should look like this: 1-4, 7-9, 13, 16-17.
EDIT:
I used the first answer at #CMS' link for my Script. Looks pretty much like a shorter version of #corschdi's snippet:
var ar = [1,2,3,4,7,8,9,13,16,17];
var getRanges = function(array) {
var ranges = [], rstart, rend;
for (var i = 0; i < array.length; i++) {
rstart = array[i];
rend = rstart;
while (array[i + 1] - array[i] == 1) {
rend = array[i + 1]; // increment the index if the numbers sequential
i++;
}
ranges.push(rstart == rend ? rstart+'' : rstart + '-' + rend);
}
return ranges;
}
alert(getRanges(ar));
In your code, lastValue never changes in the loop, so you're forever comparing against the first element in the array. Also, when you do find a match, you aren't yet ready to append to the pages result just yet--there might be more numbers to come.
One approach might be to keep a run of the current sequence of numbers (or just the first and last numbers in a run), and only append this run to the result string whenever we find a break in the sequence or hit the end of the string.
There are many ways to approach this, and I recommend checking other folks' answers at the Codewars: Range Extraction kata, which is (almost) identical to this problem.
Here's my solution:
const rangeify = a => {
const res = [];
let run = []
for (let i = 0; i < a.length; i++) {
run.push(a[i]);
if (i + 1 >= a.length || a[i+1] - a[i] > 1) {
res.push(
run.length > 1 ? `${run[0]}-${run.pop()}` : run
);
run = [];
}
}
return res.join(", ");
};
[
[1,2,3,4,7,8,9,13,16,17],
[],
[1],
[1, 2],
[1, 3],
[1, 2, 3, 8],
[1, 3, 4, 8],
[1, 1, 1, 1, 2, 3, 4, 5, 5, 16],
[-9, -8, -7, -3, -1, 0, 1, 2, 42]
].forEach(test => console.log(rangeify(test)));
This should work:
var array = [1, 2, 3, 4, 7, 8, 9, 13, 16, 17];
var ranges = [];
var index = 0;
while (index < array.length) {
var rangeStartIndex = index;
while (array[index + 1] === array[index] + 1) {
// continue until the range ends
index++;
}
if (rangeStartIndex === index) {
ranges.push(array[index]);
} else {
ranges.push(array[rangeStartIndex] + " - " + array[index]);
}
index++;
}
console.log(ranges.join(", "));
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