Related
I would like to keep the original array to return the original index in recursive function.
The original code is from rbarilani https://gist.github.com/rbarilani/0d7946510740f9e1e8fa .
Please help to advise how to change the line
const numList = [3,9,8,4,5.5,7,10.07];
function subsetSum(numbers, target, partial) {
var s, n, remaining;
const numList = [3,9,8,4,5.5,7,10.07]; **//<<<<<<<The code I want to change, please advise how to make it as function input**
partial = partial || [];
// sum partial
s = partial.reduce(function (a, b) {
return Math.round((a + b)*100)/100;
}, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log(numList);
partial.forEach(function(findIndex){
console.log(findIndex, 'is at position ', numList.indexOf(findIndex));
});
}
for (var i = 0; i < numbers.length; i++) {
n = numbers[i];
remaining = numbers.slice(i + 1);
subsetSum(remaining, target, partial.concat([n]));
}
}
subsetSum([3,9,8,4,5.5,7,10.07],15.57);
thank you all
You need to create a closure around your recursive function like:
function findSubSet(numList,targ){
function subsetSum(numbers, target, partial) {
var s, n, remaining;
partial = partial || [];
// sum partial
s = partial.reduce(function (a, b) {
return Math.round((a + b)*100)/100;
}, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log(numList);
partial.forEach(function(findIndex){
console.log(findIndex, 'is at position ', numList.indexOf(findIndex));
});
}
for (var i = 0; i < numbers.length; i++) {
n = numbers[i];
remaining = numbers.slice(i + 1);
subsetSum(remaining, target, partial.concat([n]));
}
}
subsetSum(numList,targ);
}
findSubSet([3,9,8,4,5.5,7,10.07],15.57);
Your function subsetSum() does not return anything, so it is more like a recursive procedure really. Everything in your code stays the same, the only change I made was to create the function findSubSet() around it, so it keeps the original numList array in its scope to be used by all recursive calls of subsetSum().
Using the closure idea, you can simplify your code even further, as the target value is another variable that does not need to be passed down:
function findSubSet(numList,target){
function subsetSum(numbers,partial) {
var s, n, remaining;
// sum partial
s = partial.reduce((a, b)=>Math.round((a + b)*100)/100, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log("found a subset in "+numList.join(" ")+" for target "+target+":");
partial.forEach(idx=>console.log(idx, 'is at position ', numList.indexOf(idx)));
}
for (var i = 0; i < numbers.length; i++)
subsetSum(numbers.slice(i + 1), partial.concat([numbers[i]]));
}
subsetSum(numList,[]);
}
findSubSet([3,9,8,4,5.5,7,10.07],17.5);
I will recommend generators as they are perfectly suited for this kind of problem. The benefit of the generator is that it is pauseable and cancellable. This allows you to easily find one solution to the problem, or all solutions, without having to change the code.
function* subsetSums(numbers, target, precision = 2)
{ function* solve(i, q, r)
{ if (q == 0) return yield r
if (numbers.length < i || q < 0) return
// solve with this number
yield *solve
( i + 1
, round(q - numbers[i], precision)
, [...r, {pos: i, n: numbers[i]}]
)
// solve without this number
yield *solve(i + 1, q, r)
}
yield *solve(0, target, [])
}
Notice how I separated round into its own function. Isolating concerns is an effective programming technique as it makes your functions easier to read/write and promotes code reuse within other areas of your program
const round = (n, p = 0) =>
Math.round(n * 10 ** p) / 10 ** p
We can get all solutions -
const solutions =
Array.from(subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57))
Or maybe we just want the first solution. Because generators are cancellable, this means that no work will be done after returning the first value -
function first (it)
{ for (const v of it)
return v
}
const solution =
first(subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57))
We could wrap this into a simple HTML form using some additional generic functions, stepper, which steps through any generator, and json, which creates a text node with JSON.stingify'd contents -
function* stepper (it, f)
{ let x = it.next()
while (!x.done) (yield f(x.value), x = it.next())
while (true) yield f("no more results")
}
function json(value)
{ const e = document.createElement("pre")
e.textContent = JSON.stringify(value)
return e
}
Now all we have to do is connect this to our form -
<form id="solver">
<button type="button" name="next">next</button>
<output name="output"></output>
</form>
const f =
document.forms.solver
const solver =
stepper
( subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57)
, solution =>
f.output.appendChild(json(solution))
)
f.next.addEventListener("click", _ => solver.next())
Run the snippet below to see the results in your own browser -
function* subsetSums(numbers, target, precision = 2)
{ function* solve(i, q, r)
{ if (q == 0) return yield r
if (numbers.length < i || q < 0) return
// solve with this number
yield *solve
( i + 1
, round(q - numbers[i], precision)
, [...r, {pos: i, n: numbers[i]}]
)
// solve without this number
yield *solve(i + 1, q, r)
}
yield *solve(0, target, [])
}
function* stepper (it, f)
{ let x = it.next()
while (!x.done) (yield f(x.value), x = it.next())
while (true) yield f("no more results")
}
function json(value)
{ const e = document.createElement("pre")
e.textContent = JSON.stringify(value)
return e
}
const round = (n, p = 0) =>
Math.round(n * 10 ** p) / 10 ** p
const f =
document.forms.solver
const solver =
stepper
( subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57)
, solution =>
f.output.appendChild(json(solution))
)
f.next.addEventListener("click", _ => solver.next())
<form id="solver">
<button type="button" name="next">next</button>
<output name="output"></output>
</form>
[{"pos":0,"n":3.27},{"pos":3,"n":6.8},{"pos":5,"n":5.5}]
[{"pos":5,"n":5.5},{"pos":7,"n":10.07}]
"no more results"
The numbers input is not modified as a result of running subsetSums.
I'm stuck on a problem that requires me to display the full workings of a factorial function, for example, if the user wanted to workout 6!, i would need to display: 6 * 5 * 4 * 3 * 2 * 1 = 720. Would i need to use an array for such?
This is what i have so far in order to workout the factorized value of any user given number, although this only outputs the final value, and not the fully expanded working out as i have shown above:
(the variable number contains the user input);
var f = [];
function factorizeFunction(number) { //this is the function that does the factorization calculations
if (number == 0 || number == 1)
return 1;
if (f[number] > 0)
return f[number];
return f[number] = factorizeFunction(number-1) * number;
}
document.getElementById("factorialTest").innerHTML = factorizeFunction(number);
any help on this would be appreciated!
One option is, on each iteration, push to an array which is passed down through the recursive call (or created on the initial call). At the end, return the array, joined by *, and also the sum of the array:
function factorizeFunction(number, arr = []) { //this is the function that does the factorization calculations
if (number == 0 || number == 1) arr.push(number);
else {
arr.push(number);
factorizeFunction(number - 1, arr);
}
return arr.join(' * ') + ' = ' + arr.reduce((a, b) => a * b, 1);
}
document.getElementById("factorialTest").innerHTML = factorizeFunction(5);
<div id="factorialTest"></div>
Use map and join methods.
const factorString = num => {
const nums = new Array(num).fill(0).map((_, i) => num - i);
let res = 1;
nums.forEach(x => res *= x);
return `${nums.join(' * ')} = ${res}`;
}
console.log(factorString(6))
You could change the return signature of the function and expect an array of an array with the factors and the product.
function factorize(number) {
if (number === 0 || number === 1) return [[1], 1];
var [factors, product] = factorize(number - 1);
return [[...factors, number], product * number];
}
console.log(factorize(5));
Ive been reading everything online but its not exactly what I need
var x = 'a1b2c3d4e5'
I need something to get me to
using 1 the answer should be abcde
using 2 the answer should be 12345
using 3 the answer should be b3e
the idea behind it if using 1 it grabs 1 skips 1
the idea behind it if using 2 it grabs 2 skips 2
the idea behind it if using 3 it grabs 3 skips 3
I dont want to use a for loop as it is way to long especially when your x is longer than 300000 chars.
is there a regex I can use or a function that Im not aware of?
update
I'm trying to some how implement your answers but when I use 1 that's when I face the problem. I did mention trying to stay away from for-loops the reason is resources on the server. The more clients connect the slower everything becomes. So far array.filter seem a lot quicker.
As soon as I've found it I'll accept the answer.
As others point out, it's not like regular expressions are magic; there would still be an underlying looping mechanism. Don't worry though, when it comes to loops, 300,000 is nothing -
console.time('while')
let x = 0
while (x++ < 300000)
x += 1
console.timeEnd('while')
// while: 5.135 ms
console.log(x)
// 300000
Make a big string, who cares? 300,000 is nothing -
// 10 chars repeated 30,000 times
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 2
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 31.990ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegiacegia...
// 150000
Or use an interval of 3 -
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 3
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 25.055ms
console.log(result)
console.log(result.length)
// adgjcfibehadgjcfibehadgjcfibehadgjcfibe...
// 100000
Using a larger interval obviously results in fewer loops, so the total execution time is lower. The resulting string is shorter too.
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 25 // big interval
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 6.130
console.log(result)
console.log(result.length)
// afafafafafafafafafafafafafafafafafafafafafafa...
// 12000
You can achieve functional style and stack-safe speed simultaneously -
const { loop, recur } = require('./lib')
const everyNth = (s, n) =>
loop
( (acc = '', x = 0) =>
x >= s.length
? acc
: recur(acc + s[x], x + n)
)
const s = 'abcdefghij'.repeat(30000)
console.time('loop/recur')
const result = everyNth(s, 2)
console.timeEnd('loop/recur')
// loop/recur: 31.615 ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegia ...
// 150000
The two are easily implemented -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc = f()
while (acc && acc.recur === recur)
acc = f(...acc.values)
return acc
}
// ...
module.exports =
{ loop, recur, ... }
And unlike the [...str].filter(...) solutions which will always iterate through every element, our custom loop is much more flexible and receives speed benefit when a higher interval n is used -
console.time('loop/recur')
const result = everyNth(s, 25)
console.timeEnd('loop/recur')
// loop/recur: 5.770ms
console.log(result)
console.log(result.length)
// afafafafafafafafafafafafafafa...
// 12000
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc = f()
while (acc && acc.recur === recur)
acc = f(...acc.values)
return acc
}
const everyNth = (s, n) =>
loop
( (acc = '', x = 0) =>
x >= s.length
? acc
: recur(acc + s[x], x + n)
)
const s = 'abcdefghij'.repeat(30000)
console.time('loop/recur')
const result = everyNth(s, 2)
console.timeEnd('loop/recur')
// loop/recur: 31.615 ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegia ...
// 150000
Since I'm not an expert of regex, I'd use some fancy es6 functions to filter your chars.
var x = 'a1b2c3d4e5'
var n = 2;
var result = [...x].filter((char, index) => index % n == 0);
console.log(result);
Note that because 0 % 2 will also return 0, this will always return the first char. You can filter the first char by adding another simple check.
var result = [...x].filter((char, index) => index > 0 && index % n == 0);
As a variant:
function getNth(str, nth) {
return [...str].filter((_, i) => (i + 1) % nth === 0).join('');
}
console.log(getNth('a1b2c3d4e5', 2)); // 12345
console.log(getNth('a1b2c3d4e5', 3)); // b3e
What I'd suggest, to avoid having to iterate over the entire array, is to step straight into the known nth's.
Here's a couple of flavors:
function nthCharSubstr(str, nth) {
let res = "";
for (let i = nth - 1; i < str.length; i += nth) {
res += string[i];
}
return res;
}
More ES6-y:
const nthCharSubstr = (str, nth) =>
[...Array(parseInt(str.length / nth)).keys()] // find out the resulting number of characters and create and array with the exact length
.map(i => nth + i * nth - 1) // each item in the array now represents the resulting character's index
.reduce((res, i) => res + str[i], ""); // pull out each exact character and group them in a final string
This solution considers this comment as being valid.
Say I want to build an array of numbers base 8, or base 26, I'm not sure how to approach a general formula for doing this:
console.log(arrayOfNumbersOfBase(8, 0, 10));
console.log(arrayOfNumbersOfBase(26, 0, 10));
function arrayOfNumbersOfBase(base, start, size)
{
var array = [];
for (var i = start, n = size; i < n; i++)
{
array.push(i * (base));
}
return array;
}
You can take the next approach as a starting point, basically I had to define some utility methods:
mapToChar(n) maps a number n to a character representation, for example, 10 is mapped to 'A'.
convertToBaseN(n, base) converts the number n to his representation on the given base. This method uses a recursive approach and utilizes the previous one.
Finally, generateNumbersOfBase(base, start, size) generates an array of size elements starting with the number start for the given base.
CODE:
// Next utility method map a decimal number to a character representation.
const mapToChar = (n) =>
{
n = (n >= 0 && n <= 9) ? '0'.charCodeAt() + n : n - 10 + 'A'.charCodeAt();
return String.fromCharCode(n);
}
// Next utility method convert a decimal number to his base-n representation.
const convertToBaseN = (n, base, res = "") =>
{
if (n <= 0)
return (res && res.split("").reverse().join("")) || "0";
// Convert input number to given base by repeatedly
// dividing it by base and taking remainder.
res += mapToChar(n % base);
return convertToBaseN(Math.floor(n / base), base, res);
}
// Next method generates an array of numbers for a given base.
const generateNumbersOfBase = (base, start, size) =>
{
return Array(size).fill(0).map((x, idx) => convertToBaseN(start + idx, base));
}
// Finally, generate some arrays.
let base10Array = generateNumbersOfBase(10, 15, 5);
let base2Array = generateNumbersOfBase(2, 5, 9);
let base16Array = generateNumbersOfBase(16, 10, 12);
let base8Array = generateNumbersOfBase(8, 1, 12);
console.log(
JSON.stringify(base10Array),
JSON.stringify(base2Array),
JSON.stringify(base16Array),
JSON.stringify(base8Array),
);
Now, if you need to convert some base-n representation back to decimal number, you can use next approach:
const convertToDec = (str, base) =>
{
let codeA = 'A'.charCodeAt();
let code0 = '0'.charCodeAt();
return str.split("").reverse().reduce((acc, c, idx) =>
{
let code = c.charCodeAt();
c = code + ((c >= '0' && c <= '9') ? -code0 : -codeA + 10);
return acc += c * Math.pow(base, idx);
}, 0);
}
// Lets convert back some arrays generated on the previous exampel
let base2Array = ["101","110","111","1000","1001","1010","1011","1100","1101"];
let base16Array = ["A","B","C","D","E","F","10","11","12","13","14","15"];
let res2 = base2Array.map(x => convertToDec(x, 2));
let res16 = base16Array.map(x => convertToDec(x, 16));
console.log(
JSON.stringify(res2),
JSON.stringify(res16)
);
I want to add two numbers from range 10-99,for example:
Input:16
Output:1+6=7
Input:99
Output:18
function digital_root(n) {
var z = n.toString().length;
if (z == 2) {
var x = z[0] + z[1]
return x;
}
}
console.log( digital_root(16) );
Output from this code is NaN.What should I correct?
You can try this:
function digital_root(n) {
var z = n.toString();
//use length here
if (z.length == 2) {
//convert to int
var x = parseInt(z[0]) + parseInt(z[1]);
return x;
} else {
return "not possible!";
}
}
console.log( digital_root(16) );
console.log( digital_root(99) );
console.log( digital_root(999) );
Use split to split the string in half and add the two using parseInt to convert to a number.
const sum = (s) => (''+s).split('').reduce((a,b) => parseInt(a)+parseInt(b))
↑ ↑ ↑ ↑
our coerce split sum
function to string in two both
Here a test :
const sum = (s) => (''+s).split('').reduce((a,b) => parseInt(a)+parseInt(b))
console.log(sum(12))
There are several approaches to sum digits of a number. You can convert it to a string but IDK if thats neccesary at all. You can do it with numerical operations.
var input = 2568,
sum = 0;
while (input) {
sum += input % 10;
input = Math.floor(input / 10);
}
console.log(sum);
Here's a fun short way to do it:
const number = 99
const temp = number.toString().split('')
const res = temp.reduce((a, c) => a + parseInt(c), 0) // 18
1.) Convert number to string
2.) Separate into individual numbers
3.) Use reduce to sum the numbers.
Your way would be the iterational way to solve this problem, but you can also use a recursive way.
Iterative solution (Imperative)
n.toString() Create String from number.
.split("") split string into chars.
.reduce(callback, startValue) reduces an array to a single value by applying the callback function to every element and updating the startValue.
(s, d) => s + parseInt(d) callback function which parses the element to an integer and adds it to s (the startValue).
0 startValue.
Recursive solution (Functional)
condition?then:else short-hand if notation.
n<10 only one digit => just return it.
n%10 the last digit of the current number (1234%10 = 4).
digital_root_recurse(...) call the function recursivly.
Math.floor(n / 10) Divide by 10 => shift dcimal point to left (1234 => 123)
... + ... add the last digit and the return value (digital root) of n/10 (1234 => 4 + root(123)).
function digital_root_string(n) {
return n.toString().split("").reduce((s, d) => s + parseInt(d), 0);
}
function digital_root_recurse(n) {
return n < 10 ? n : n % 10 + digital_root_recurse(Math.floor(n / 10));
}
console.log(digital_root_string(16));
console.log(digital_root_string(99));
console.log(digital_root_recurse(16));
console.log(digital_root_recurse(99));
The issue in your code is that you stored the length of n into z. The length is an integer, so both z[0] and [1] are undefined. The solution is to store the string into another variable and use that instead of z.
function digital_root(n) {
n = n.toString();
var l = n.length;
if (l === 2) {
return parseInt(n[0], 10) + parseInt(n[1], 10);
}
}
console.log( digital_root(16) );
Simply use var x = parseInt(n/10) + (n%10); and it will work for you.
function digital_root(n) {
var z = n.toString().length;
if (z == 2) {
var x = parseInt(n/10) + (n%10);
return x;
}
}
console.log( digital_root(16) );
console.log( digital_root(99) );
console.log( digital_root(62) );
Convert input to string, split it, convert each item back to number and sum them all:
function digital_root(n) {
return String(n).split('').map(Number).reduce((a,b) => a + b)
}
const result = digital_root(99);
console.log(result);