I am doing a challenge on Coderbyte and I would be grateful for any advice on my question:
The challenge given to me:
"Using the JavaScript language, have the function ArrayAdditionI(arr)
take the array of numbers stored in arr and return the string true if
any combination of numbers in the array can be added up to equal the
largest number in the array, otherwise return the string false.
For example: if arr contains [4, 6, 23, 10, 1, 3] the output should
return true because 4 + 6 + 10 + 3 = 23. The array will not be empty,
will not contain all the same elements, and may contain negative numbers. "
The way I attempted to solve it: http://jsfiddle.net/reLsg0fg/
function ArrayAdditionI(arr){
var newArr=arr.sort(); // sorted from smallest to largest.
var largestNum=newArr.slice(-1); // Gets the last number, which would be the largest.
var loopArr=arr.sort().pop(); // Takes out the largest number for adding later.
var result=0;
for(var i=0; i<loopArr.length; i++){ // loops through all numbers.
if(result/largestNum !== 1){ //when you divide a number by itself it will be 1.
result+=loopArr[i]; // keep adding each number until get largest number.
}else if(result === largestNum){
return true;
}
}
return false;
}
// TESTS
console.log("-----");
console.log(ArrayAdditionI([4,6,23,10,1,3]));
console.log(ArrayAdditionI([5,7,16,1,2]));
console.log(ArrayAdditionI([3,5,-1,8,12]));
I'm supposed to get true, false, true. But I get false, false, false as if something is wrong within my loop. JSFiddle: http://jsfiddle.net/reLsg0fg/
I would appreciate any suggestions. Thank you ^^
Sort Array using
arr.sort(function (a, b) { return a - b })
I have tried to solve this problem with a for loop but I missed the fact that the challenge
is not asking that all numbers need to add up to equal the largest num, but it is also possible to
add up to the largest num if we take some numbers out. Thus I decided to solve with recursion.
Tips:
* The Math.max.apply() method takes an array and returns the largest number. Note that it usually works on strings as Math.max().
* the sort() method can take a parameter to further expand it's purpose. Usually it only
sorts strings, but to sort numbers we include a function that finds which number is bigger.
* First get the largest number.
* Sort the array and remove the largest number to be used for recursion later.
* Create a recursion function that checks if the numbers add up to the largest number, and if not, check that if some numbers in array are subtracted from the largest num they are equal to the largest number.
function ArrayAdditionI(array){
var largestNum = Math.max.apply(0, array); // gets the largest number in array.
array.sort(function(a,b){ return a-b;}).pop(); // sorts array and removes last(largest) number.
function recursionCheck(arr, sum){
// the base case when array empty.
if(arr.length === 0){
return sum === 0;
}
var arrBeginNum=arr[0];
// for every recursion take away one number(the first one in this case).
arr = arr.slice(1);
// first check if numbers sum up to largest num if not, check if removing numbers adds up to largest num.
return recursionCheck(arr, sum) || recursionCheck(arr, sum - arrBeginNum);
}
// recursion needs to be called for it to start.
return recursionCheck(array, largestNum);
}
// TESTS
console.log("-----");
console.log(ArrayAdditionI([1,2,3,5,4])); ==> true
console.log(ArrayAdditionI([21,10,12,9,2])); ==> true
console.log(ArrayAdditionI([4,6,23,10,1,3])); ===> true
console.log(ArrayAdditionI([5,7,16,1,2])); ===> false
console.log(ArrayAdditionI([3,5,-1,8,12])); ===> true
This might not be the complete solution yet, but here are the JavaScript-Problems:
largestNum was an array in you algorithm
.sort() was not working
function ArrayAdditionI(arr){
var largestNum = Math.max.apply(0, arr); // Gets the last number, which would be the largest.
arr.sort(function(a, b){return a-b})
arr.pop(); // Takes out the largest number for adding later.
var result=0;
Also use if(result !== largestNum) {, Division is expensive and might have unexpected results with floating-point numbers.
Thats it for your JavaScript. But I am pretty sure the Algorithm is wrong - but I think this is up to you
Note that the example [4, 6, 23, 10, 1, 3] => 4 + 6 + 10 + 3 = 23 is not just adding up the lowest to the biggest value to try and match it.
A possible example of a solution for the problem.
How this works:
First sort all items descending
Shift the first element to largest
Call the recursive function y with the reduced array, the largest value and a variable which holds an empty array for the successfully added items.
The recursive function works basically in two parts
Test if the remaining sum is zero, if so the result is achieved and return true, which finished the function.
If not iterate through the array and
Make a copy from the array
Get the value from the position with splice
Test, if the value is smaller or equal the remaining sum and the result of the call of y with the shorted array, sum minus value and a new array with the used items and the acual item.
If true return true and finish the function.
If not finished before return false.
function x(array) {
function y(a, s, result) {
var aa, i, v;
if (s === 0) {
document.write('<pre>result: ' + JSON.stringify(result, 0, 4) + '</pre>');
return true;
}
for (i = 0; i < a.length; i++) {
aa = a.slice();
v = aa.splice(i, 1)[0];
if (v <= s && y(aa, s - v, result.concat(v))) {
return true;
}
}
return false;
}
var largest,
r = [];
array.sort(function (a, b) { return b - a; });
largest = array.shift();
document.write('largest value: ' + largest + '<br>');
return y(array, largest, r);
}
document.write(x([4, 6, 23, 10, 1, 3]) + '<hr>');
document.write(x([5, 7, 16, 1, 2]) + '<hr>');
document.write(x([3, 5, -1, 8, 12]));
Thanks #mar
Here is a version in Kotlin if someone needs
private fun returnResult(arr: Array<Int>): Boolean {
arr.sort()
val largestNumber = arr.last()
val arrWithoutLargest = arr.dropLast(1).toTypedArray()
return recursionCheck(arrWithoutLargest, largestNumber)
}
private fun recursionCheck(arr: Array<Int>, sum:Int): Boolean {
if (arr.isEmpty()) return sum == 0
val arrBeginNum = arr[0]
val arr2 = arr.drop(1).toTypedArray()
return recursionCheck(arr2, sum) || recursionCheck(arr2, sum - arrBeginNum)
}
Related
I am trying to find the average the sum of digits of a number.
For example, for the number 123, the sum of digits of 123 is 6 and the number of digits in 123 is 3.
So, the average of digits of 123 is 6/3 = 2.
I've only gotten as far as trying to find the sum through recursion unfortunately and often comes up as undefined. If I could figure this out I could find the average comfortably.
function averageOfDigits(number) {
// Make the whole number into a string first to get the individual digits
let arrOfStr = number.toString().split('');
// Convert this array into integers
let arrOfNum = arrOfStr.map(parseFloat)
// Find sum of these digits using recursion
let sum = function sumRecursion (arrOfNum) {
if (arrOfNum.length === 1) {
return arrOfNum[0]
} else {
return arrOfNum.pop() + sum(arrOfNum)
}
}
}
console.log(averageOfDigits(999))
You were close. Your implementation is setting sum equal to the recursive function, so that function is never getting called inside averageOfDigits. I think the confusing part was referring to the same function by two different names.
Here I define the sum function once, then call it twice. First is the internal recursive call, and second is in the return statement.
function averageOfDigits(number) {
// Make the whole number into a string first to get the individual digits
let arrOfStr = number.toString().split('');
// Convert this array into integers
let arrOfNum = arrOfStr.map(parseFloat)
// Find sum of these digits using recursion
function sum(arrOfNum) {
if (arrOfNum.length === 1) {
// base case reached
return arrOfNum[0];
} else {
// return first digit + recursive call
return arrOfNum.pop() + sum(arrOfNum);
}
}
return sum(arrOfNum);
}
console.log(averageOfDigits(999))
You can finish off the averageOfDigits function by replacing the return statement with your own code. Right now it just returns the sum.
It's missing the initial call to the recursive function.
Hint:
return (function sum(arr) {
if (arr.length === 1) {
return arr[0]
} else {
return arr.pop() + sum(arr)
}
}(arrOfNum))
There are several interesting alternative recursive approaches. Our first one treats the number as a string and proceeds from there:
const _avgOfDigits = ([d, ...ds], total, count) =>
d == undefined
? total / count
: _avgOfDigits (ds, total + Number (d), count + 1)
const avgOfDigits = (n) =>
_avgOfDigits (String (n) .split (''), 0, 0)
console .log (avgOfDigits (8675309)) //=> 5.428571428571429
Here we have a shell function that turns our number into an array of single-digit strings, then calls the private recursive function passing that array, and zeros for total and count. Our private function separates off the first digit and adds it to the total, increments the count, and recurs with these values and the remaining digits. When there are no more digits we return the quotient of the total and the digit count.
Our second one is more mathematical:
const avgOfDigits = (n, total = 0, count = 0) =>
n == 0
? total / count
: avgOfDigits (Math .floor (n / 10), total + n % 10, count + 1)
console .log (avgOfDigits (8675309)) //=> 5.428571428571429
Here we deal with the last digit and the remaining ones independently, turning, say, 8675309 into 9 and 867530, and using the 9 to increase our total, again incrementing our count, and recurring with 867530 and these new values. The recursion bottoms out the same way, and we return the same quotient.
A final sample is not recursive, showing an interesting running calculation for our average, not explicitly storing a total anywhere, and deriving the count from the running index:
const avgOfDigits = (n) => String (n) .split ('') .reduce (
(avg, digit, idx) => (avg * idx + Number (digit)) / (idx + 1),
0
)
console .log (avgOfDigits (8675309)) //=> 5.428571428571429
Here we keep a running average, which we adjust using the index as a count of digits seen so far. The efficiency will suffer because on each iteration, we are not just adding two numbers but also performing a multiplication and a division. And it offers little over other simpler versions, but a variant of it could be used successfully with some sort of scan function.
Update
I didn't explain what I meant by that scan comment. The idea is simple enough. scan is a function that acts like reduce but keeps all the partially accumulated values. So scan ((a, b) => a + b)) (0) ([1, 2, 3, 4, 5]) //=> [1, 3, 6, 10, 15], which is [(1), (1 + 2), (1 + 2 + 3), (1 + 2 + 3 + 4), (1 + 2 + 3 + 4 + 5)].
It's easy enough to write a scan function, and with one of those, this style of averaging may become more useful. For example,
const scan = (fn) => (init) => (xs) =>
xs .reduce ((a, x, i) => a .concat (fn (i == 0 ? init : a [i - 1], x, i)), [])
const digitAvgs = scan (
(avg, digit, idx) => (avg * idx + Number (digit)) / (idx + 1),
) (0)
console .log (digitAvgs ([8, 6, 7, 5, 3, 0, 9]))
The solution that i've been working on so far:
function solution(elements) {
let numOfShifts;
let shift = shiftedArray(elements);
for(i = 0; i < shift.length; i++){
//Here is where i'm getting stuck... how do i continue through the loop even after the first false is returned
//until all arrays are checked for equality?
if(areEqual(shift[i])){
numOfShifts = i
}else return -1;
}
return numOfShifts;
};
function shiftedArray(array){
let shiftedArrays = [];
for(let i = array.length -1 ; i >= 1; i--){
// first element is simply a formula to create chunk 1
let firstElement = array.length - (i % array.length);
//the result of first element.
let chunk1 = array.slice(firstElement);
//the remaining numbers
let chunk2 = array.slice(0, firstElement);
//Copy of both chunks now merged and pushed into shifted arrays
shiftedArrays.push([...chunk1, ...chunk2]);
};
return shiftedArrays;
}
function areEqual(shift){
let sortedShift = [...shift].sort((a ,b) => {
return a - b
});
//takes in a single shift and does a deep check to see if the array is equal to sorted version
if(sortedShift.length === shift.length){
return sortedShift.every((element, index) => {
if(element === shift[index]){
return true;
}
return false;
})
}
}
console.log(solution([1,4,2,3]));
console.log(solution([[2, 3, 4, 5, 6, 7, 8, 9, 10, 1]]))
How do I keep the for loop running even after the first false is returned from the areEqual() function?
A side note: I understand that this could probably use some refactoring... like, I was working on this with someone earlier and they mentioned how I can simply shift the array by writing a helper function like shiftArray(arr){return arr.push(arr.pop())} but I don't get how that implementation would work considering that all that's returned is the value that was taken out of the array, not the new shifted array.
You may be doing too much work.
Say you have an array A of n integers, zero indexed.
Parse the array from index 0 to n mod n (so 0 twice). Count the number of pairs where the latter integer is less than the former, and store the first index where this happens.
If the count is 1 and the location is k (so A[k] < A[k-1]), then a cyclic shift of either -k or n-k will convert A to a sorted array. If the count is greater than 1 then there's no solution.
E.g., [4,5,0,1,2,3] -- we see k=2 is the only index which has a value below its predecessor, and a cyclic shift of -2 or 4 forms [0,1,2,3,4,5] which is sorted.
This is part of a much bigger algorithm problem that I am trying to solve.
I am trying to create an array of all numbers less than num.
Here is my Code:
function sum(num, arr = []) {
if (num == 0) {
return arr;
}
arr.push(num);
return sum(num - 1);
}
console.log(sum(10));
I tried declaring arr as a variable and as an argument. I can’t see why it returns an empty array.
How can I fix the array so that it doesn’t return an empty array?
The broader question if you are interested is:
In number theory and combinatorics, a partition of a positive integer n, also called an integer partition, is a way of writing n as a sum of positive integers. Two sums that differ only in the order of their summands are considered the same partition. If order matters, the sum becomes a composition. For example, 4 can be partitioned in five distinct ways:
4
3 + 1
2 + 2
2 + 1 + 1
1 + 1 + 1 + 1
The problem with your first snippet is that you don't pass arr into sum. If you do, you get the array:
function sum(num, arr = []) {
if (num == 0) {
return arr;
}
arr.push(num);
return sum(num - 1, arr);
// ^^^−−−−−−−−−−−−−−−−−−−−−−−−
}
console.log(sum(10));
It returns empty array because you did not send in the second parameter, which is arr, hence each recursion is initialized with an empty array.
function sum(num, arr = []) {
if (num == 0) {
return arr;
}
arr.push(num);
return sum(num - 1, arr);
}
console.log(sum(10));
I was wondering how this worked, and what each part meant.
const factors = number => [...Array(number + 1).keys()].filter(i=>number % i === 0);
I have done some research on some of the bits but I don't really understand how it goes together as a whole. Thanks in advance :)
Let's break it down:
Array(number + 1): Creates an array with number + 1 empty elements
Array(number + 1).keys(): Retrieves the indices of the array in the form of an iterator
[...Array(number + 1).keys()]: Creates an array from the iterator (contains elements 0, 1, 2, ..., (number - 1), number)
.filter(cb): Calls the function cb for each value in the array, and returns a new array containing the values for which the callback (cb) has returned true (uses implicit boolean conversion)
i => number % i === 0: Gets called for each value of the array, current element stored to i
number % i: Divides number with i and returns the remainder
number % i === 0: Checks if the remainder equal to zero (i.e. if number perfectly divisible by i)
.filter(i => number % i === 0): Filters the array, keeping the elements that are the divisors of number
So,
number => [...Array(number + 1).keys()].filter(i => number % i === 0);
creates a function, that returns an array with the divisors of the given number.
Let's break it down...
Array(number + 1)
This is the array constructor, creating a sparse array with length number + 1
.keys()
Using Array.prototype.keys() to get an iterator for the array keys which are [0, number]
FYI, this is interval notation, not an array
[...Array(number + 1).keys()]
Using the spread syntax on an iterator converts it to an array, so now we have something like
[0, 1, 2, ..., number]
.filter(i=>number % i === 0)
Uses Array.prototype.filter() to reduce the ranged array above to one where the values divide evenly into number
A low-fi version of this might look something like
function factors(number) {
const factors = []
for (let i = 0; i <= number; i++) {
if (i % number === 0) {
factors.push(i)
}
}
return factors
}
For clarity sake, this is what I mean. I want to look for the two least numbers in an array(sorted) that will generate a particular number. The steps go thus:
Loop through the array and each time set a current value that other
numbers will be deducted from.
Keep doing that till you find the numbers that match the problem and return them.
Example. I need two numbers that when subtracted from the array will give a result of 2.
let givenArray = [1, 4, 8, 10];
The subtraction should go thus: 4 - 1 = 3(doesn't match); //continue
8 - 4 = 1(doesn't match);// continue
8 - 1 = 7(doesn't match); //continue
10 - 8 = 2(match found); //stop and return 8, 10.
NOTE: This same array may contain a 6 and 8 or 8 and 10 that will both yield 2 but 6 and 8 should be returned instead. The way the array is generated isn't of much importance.
P.S: I eventually solved it yesterday but I won't mind other ideas on how to go about it.
This solution takes the advantage of a hash table and uses a single loop approach for getting the two values out of an array to balance two values.
First, take the absolute delta of the two values of arrayA and take this for getting the values out of the greater array.
Then reduce the greater array arrayB by checking if the needed value exist and if the sum is smaller then a previously found set.
The argument for checking is build out of the absolute delta of delta and v, the actual value of the array or by taking the sum of delta and v.
The last point, and to make this all working, the actual value v is included into the hash table, for a later look up.
The result is either an array of two values, which balance the other two values or undefined, if no values are found.
var arrayA = [3, 5],
arrayB = [2, 9, 5, 4],
delta = Math.abs(arrayA[0] - arrayA[1]),
values = {},
result = arrayB.reduce((r, v) => {
function check(w) {
if (!values[w] || r && r[0] + r[1] < v + w) return;
r = [w, v];
}
check(Math.abs(delta - v));
check(delta + v);
values[v] = true;
return r;
}, undefined);
console.log(result);
I'm not sure I understood correctly, but perhaps this is what you need:
let result = arrayA[1] - arrayA[0];
let i, j;
for (i = arrayB.length - 1; i >= 1; i--) { // Set the first value
for (j = arrayB.length - 1; j >= 1; j--) { // Set the second value
if (i !== j) {
if (
arrayB[i] - arrayB[j] === result // Check substraction
|| arrayB[i] + arrayB[j] === result // Check addition
) return [arrayB[i], arrayB[j]];
}
}
}