Related
How many ways can you make the sum of a number?
From wikipedia: https://en.wikipedia.org/wiki/Partition_(number_theory)#
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
Examples
Basic
sum(1) // 1
sum(2) // 2 -> 1+1 , 2
sum(3) // 3 -> 1+1+1, 1+2, 3
sum(4) // 5 -> 1+1+1+1, 1+1+2, 1+3, 2+2, 4
sum(5) // 7 -> 1+1+1+1+1, 1+1+1+2, 1+1+3, 1+2+2, 1+4, 5, 2+3
sum(10) // 42
Explosive
sum(50) // 204226
sum(80) // 15796476
sum(100) // 190569292
My Attempt
I tried to loop through two arrays simultaneously and test them against eachother. This doesn't work (at least in the way I did it) for a few reasons.
My Code:
function sum(num, arr = []) {
if(num == 0){
return testNumbers(arr, num);
}
arr.push(num);
return sum(num - 1, arr);
function testNumbers(arrr, n){
let arr2 = [...arrr];
let count = 0;
let calculations = arrr.filter((item)=>{
return item + arr2.map((a)=>{
return a;
}) == n;
})
console.log(calculations);
}
}
console.log(sum(10));
You don't need to fix my code, as I don't think its salvageable, but how do you solve the problem?
This is in fact a fairly simple recursion, if we think of the problem as counting the partitions with a given lower bound. We have two simple bases cases of 0 and 1 if the lower bound is greater than our target number or equal to it. Otherwise we recur in two ways, one for when we use that lower bound, and one for when we don't. Here's one version, where lb is the lower bound of the numbers to use:
const count = (n, lb = 1) =>
lb > n
? 0
: lb == n
? 1
: count (n - lb, lb) + count (n, lb + 1)
This counts the number of partitions with the given lower bound. So count(10, 3) would yield 5, one for each array in [[3, 3, 4], [3, 7], [4, 6], [5, 5], [10]]. Although the default value for the lower bound means that we can call it with just our target number, there are potential issues with this if we tried, say, to map over it. So it might be best to wrap this in a separate function, const countPartitions = (n) => count (n, 1)
const count = (n, lb) =>
lb > n
? 0
: lb == n
? 1
: count (n - lb, lb) + count (n, lb + 1)
const countPartitions = (n) => count (n, 1)
console .log ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .map (countPartitions))
But this will be quite slow for larger input. My test for 100 took 56.3 seconds.) If we memoize the intermediate results, we should speed things up a great deal. We can do this manually or, as I'd prefer, with a memoization helper:
const memoize = (makeKey, fn) => {
const memo = {}
return (...args) => {
const key = makeKey (...args)
return memo [key] || (memo [key] = fn (...args))
}
}
const count = memoize (
(n, lb) => `${n}~${lb}`,
(n, lb) =>
lb > n
? 0
: lb == n
? 1
: count (n - lb, lb) + count (n, lb + 1)
)
const countPartitions = (n) => count (n, 1)
console .log (countPartitions (100))
And this now takes 20 milliseconds in my test.
Update: answering comment
A comment asked
Hey Scott, sorry to bring up an old post, but I've been going over your solution here and I'm afraid I'm having trouble understanding exactly how it works. If you don't mind, could you go a little more in-depth on why counting instances of n===lb leads to the answer? Maybe my math is just weak, but I'm not following the partitions logic.
Let's imagine we're trying to partition 10, and we've already counted those whose lowest value is 1 and those whose lowest value is 2, and now we're trying to count the partitions where the lowest value is at least 3.
We call count (10, 3). Since 3 > 10 is false, we don't return 0. And since 3 == 10 is false, we don't return 1. Instead we make two recursive calls and add their results together. The first one is where we choose to use 3 in our output, choose (7, 3), since we will have seven remaining when we've selected the first 3. The second one is where we choose not to use 3 in our output, choose (10, 4), since the lowest bound will be 4 if we are to skip 3, but we still have ten to partition.
The call structure would look like this:
(10, 3)
___________________________________/\____________________
/ \
(7, 3) + (10, 4)
___________/\___________ __________/\_________
/ \ / \
(4, 3) + (7, 4) (6, 4) + (10, 5)
____/\___ ________/\_______ ____/\____ _____/\_______
/ \ / \ / \ / \
(1, 3) + (4, 4) (3, 4) + (7, 5) (2, 4) + (6, 5) (5, 5) + (10, 6)
| | | ___/\___ | ___/\___ | _____/\_____
| | | / \ | / \ | / \
| | | (2, 5) + (7, 6) | (1, 5) + (6, 6) | (4, 6) + (10, 7)
| | | | __/\__ | | | | | ____/\____
| | | | / \ | | | | | / \
| | | | (1, 6) + (7, 7) | | | | | (3, 7) + (10, 8)
| | | | | | | | | | | | ___/\____
| | | | | | | | | | | | / \
| | | | | | | | | | | | (2, 8) + (10, 9)
| | | | | | | | | | | | | ___/\___
| | | | | | | | | | | | | / \
| | | | | | | | | | | | | (1, 9) + (10, 10)
| | | | | | | | | | | | | | |
| | | | | | | | | | | | | | |
(3>1) (4=4) (4>3) (5>2) (6>1) (7=7) (4>2) (5>1) (6=6)(5=5) (6>4) (7>3) (8>2) (9>1) (10=10)
| | | | | | | | | | | | | | |
| | | | | | | | | | | | | | |
0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 1
| | | | |
| | | | |
[[3, 3, 4], [3, 7], [4, 6],[5, 5], [10]]
We can get a speed up over Scott's solution by using the recurrence relation for the partition function that uses pentagonal numbers:
function _p(k, memo){
if (k == 0)
return 1;
if (memo[k])
return memo[k];
let result = 0;
let i = 1;
const ms = [1, 1, -1, -1];
while (true){
const n = i & 1 ? (i + 1) / 2 : -i / 2;
const pentagonal = (3*n*n - n) / 2;
if (pentagonal > k)
break;
result = result + ms[(i-1) % 4] * _p(k - pentagonal, memo);
i = i + 1;
}
return memo[k] = result;
}
function p(k){
return _p(k, {});
}
var ks = [1, 2, 3, 4, 5, 6, 10, 50, 80, 100];
for (let k of ks){
const start = new Date;
console.log(`${ k }: ${ p(k) }`);
console.log(`${ new Date - start } ms`);
console.log('');
}
I watched a youtube video where this basic permutation tree was shown. If you look at this bit of code:
function recursion(input, set = [], result = []) {
if (!input.length) {
result.push([...set].join(''));
}
for (let i = 0; i < input.length; i++) {
const newArr = input.filter((n, index) => index !== i);
set.push(input[i]);
recursion(newArr, set, result);
set.pop();
}
return result.join(', ');
}
you can see that the base case (if statement) is at the top before the parameter nums is filtered. So, my whole question is how the tree and the code makes sense because for me the code would remove one too many digits from the set array. Becuase it pops an item of when returning and doesn't it return more than two times?
Does this log add clarity?
/ entering recursion with input = [1,2,3], set = [], result = []
| looping, i = 0
| adding 1 to set
| / entering recursion with input = [2,3], set = [1], result = []
| | looping, i = 0
| | adding 2 to set
| | / entering recursion with input = [3], set = [1,2], result = []
| | | looping, i = 0
| | | adding 3 to set
| | | / entering recursion with input = [], set = [1,2,3], result = []
| | | | adding 123 to result
| | | \ returning [123]
| | | removing 3 from set
| | \ returning [123]
| | removing 2 from set
| | looping, i = 1
| | adding 3 to set
| | / entering recursion with input = [2], set = [1,3], result = [123]
| | | looping, i = 0
| | | adding 2 to set
| | | / entering recursion with input = [], set = [1,3,2], result = [123]
| | | | adding 132 to result
| | | \ returning [123,132]
| | | removing 2 from set
| | \ returning [123,132]
| | removing 3 from set
| \ returning [123,132]
| removing 1 from set
| looping, i = 1
| adding 2 to set
| / entering recursion with input = [1,3], set = [2], result = [123,132]
| | looping, i = 0
| | adding 1 to set
| | / entering recursion with input = [3], set = [2,1], result = [123,132]
| | | looping, i = 0
| | | adding 3 to set
| | | / entering recursion with input = [], set = [2,1,3], result = [123,132]
| | | | adding 213 to result
| | | \ returning [123,132,213]
| | | removing 3 from set
| | \ returning [123,132,213]
| | removing 1 from set
| | looping, i = 1
| | adding 3 to set
| | / entering recursion with input = [1], set = [2,3], result = [123,132,213]
| | | looping, i = 0
| | | adding 1 to set
| | | / entering recursion with input = [], set = [2,3,1], result = [123,132,213]
| | | | adding 231 to result
| | | \ returning [123,132,213,231]
| | | removing 1 from set
| | \ returning [123,132,213,231]
| | removing 3 from set
| \ returning [123,132,213,231]
| removing 2 from set
| looping, i = 2
| adding 3 to set
| / entering recursion with input = [1,2], set = [3], result = [123,132,213,231]
| | looping, i = 0
| | adding 1 to set
| | / entering recursion with input = [2], set = [3,1], result = [123,132,213,231]
| | | looping, i = 0
| | | adding 2 to set
| | | / entering recursion with input = [], set = [3,1,2], result = [123,132,213,231]
| | | | adding 312 to result
| | | \ returning [123,132,213,231,312]
| | | removing 2 from set
| | \ returning [123,132,213,231,312]
| | removing 1 from set
| | looping, i = 1
| | adding 2 to set
| | / entering recursion with input = [1], set = [3,2], result = [123,132,213,231,312]
| | | looping, i = 0
| | | adding 1 to set
| | | / entering recursion with input = [], set = [3,2,1], result = [123,132,213,231,312]
| | | | adding 321 to result
| | | \ returning [123,132,213,231,312,321]
| | | removing 1 from set
| | \ returning [123,132,213,231,312,321]
| | removing 2 from set
| \ returning [123,132,213,231,312,321]
| removing 3 from set
\ returning [123,132,213,231,312,321]
You can see how I added the logging to your code in this snippet:
const log = (depth, message) =>
console .log ('| '.repeat (depth) + message)
function recursion(input, set = [], result = [], depth = 0) {
log (depth, `/ entering recursion with input = [${input}], set = [${set}], result = [${result}]`)
if (!input.length) {
log (depth, `| adding ${[...set].join('')} to result`)
result.push([...set].join(''));
}
for (let i = 0; i < input.length; i++) {
log (depth, `| looping, i = ${i}`)
const newArr = input.filter((n, index) => index !== i);
log (depth, `| adding ${input[i]} to set` )
set.push(input[i]);
recursion(newArr, set, result, depth + 1);
log (depth, `| removing ${input[i]} from set` )
set.pop();
}
log (depth, `\\ returning [${result}]`)
return result.join(', ');
}
console .log (recursion([1, 2, 3]))
.as-console-wrapper {min-height: 100% !important; top: 0}
(but the console output there is limited to the last 50 lines.)
I have a table as follows:
+----+----+----+
| A | B | C |
+----+----+----+
| 1 | 2 | 3 |
+----+----+----+
| 4 | 5 | 6 |
+----+----+----+
| 7 | 8 | 9 |
+----+----+----+
| 10 | 11 | 12 |
+----+----+----+
| 13 | 14 | 15 |
+----+----+----+
| 16 | 17 | 18 |
+----+----+----+
| 19 ....
If I choose a random number (for example : 24)
The number 24 will be in C
Is there a way to know where any number will be located?
If it's just converting number to character based on this logic, you can use String.fromCharcode() like this:
const getChar = n => String.fromCharCode((n-1) % 3 + 65)
console.log(getChar(1))
console.log(getChar(2))
console.log(getChar(3))
console.log(getChar(4))
I think like this code
function get(n) {
return ['A', 'B', 'C'][(n - 1) % 3];
}
console.log(get(1)); // A
console.log(get(5)); // B
console.log(get(24)); // C
I need to get the "payment type and the customer type from this kind of string
Examples:
| D | A | B | C |
| NZ | AAA | BBB | NZ |
| AZ | CCC | DDD | AZ |
| CA | EEE | FFF | CA |
should I try the get the pattern and write a function for this? or I can find some library to detect it
so the output should be
{payment:["AAA","CCC",'EEE'],
customer:["BBB",'DDD","FFF"]}
function detect(str){
let countBar=1
let countBar2=0
let paymentLoc=NaN
let customerLoc=NaN
let after =0
let arr1=str.split(" ")
arr1=arr1.filter(item=>{return item!==""})
let newStr=''
for(let i=0;i<arr1.length;i++){
arr1[i].trim()
if(arr1[i]==='|'){
countBar++
}
if(arr1[i]==="||"){
countBar2++
}
if(arr1[i].includes("payment")){
paymentLoc=i
}
after=((countBar/(countBar2))-1)*2
let sol=[]
for(let i=0;i<arr1.length;i++){
if(arr1[i].includes("payment")){
console.log('payment index',i)
sol.push(arr1[i+after+1])
}
if(arr1[i].includes("customer")){
console.log('customer index',i)
sol.push(arr1[i+after+1])
}
}
newStr=arr1.join('')
console.log(newStr)
}
I had some fun with this one. My first thought was to use an npm package, since the string looks a lot like CSV with | as the delimiter. The package csvtojson is a good one, but why use a well-regarded library when you can hack something together?
Here's my first attempt (in Typescript):
const exampleString = ` | market | payment type | customer type | translation |
| NZ | AAA | BBB | NZ |
| AZ | CCC | DDD | AZ |
| CA | EEE | FFF | CA |`;
const cleanColumn = (col: string) =>
col
.replace("|", "")
.trim()
.replace(/\s/, "_");
const cleanRow = (row: string) =>
row
.split(/\s\|/)
.map(cleanColumn)
.filter(Boolean);
const pivotRows = (
pivoted: string[][],
currentRow: string[],
rowIndex: number
) => {
if (rowIndex === 0) {
currentRow.forEach((col, colIndex) => {
pivoted[colIndex] = [col];
});
} else {
currentRow.forEach((col, colIndex) => {
pivoted[colIndex].push(col);
});
}
return pivoted;
};
const buildObject = (
obj: { [key: string]: string[] },
currentRow: string[]
) => {
let currentCol: string;
currentRow.forEach((col, index) => {
if (index === 0) {
currentCol = col;
obj[currentCol] = [];
} else {
obj[currentCol].push(col);
}
});
return obj;
};
const detect = (str: string) =>
str
.split("\n")
.map(cleanRow)
.reduce(pivotRows, [])
.reduce(buildObject, {});
console.log(detect(exampleString));
If you look at detect, it's just executing a series of functions on the string. The first one just splits it by line-breaks. I liked what you were going for with the countBar variables, but this seemed easier.
That gives us a bunch of string arrays, which need to be broken down into columns. Here, I used some RegEx to separate everything between a combination of space and |. In cleanColumn(), I remove the remaining |s in case there are any stragglers, then replace the spaces with underscores so they can be used as object keys.
Then, remove the empty strings with the .filter(Boolean) trick (link). The last two functions are probably more verbose than necessary, but they do the job. pivotRows() uses the row and column indexes to pivot columns into rows. Last, in buildObject() the first element of each of the rows is added as the key of an object, with the rest of the values being pushed into string arrays.
Really, you should probably just use csvtojson.
Here's an attempt at just splitting by |.
var text = `| market | payment type | customer type | translation |
| NZ | AAA | BBB | NZ |
| AZ | CCC | DDD | AZ |
| CA | EEE | FFF | CA |`;
var result = {
payment: text.split('|').filter((f, i) => i-7 >= 0 && (i - 7) % 5 == 0)
.map(p => p.trim()),
customer: text.split('|').filter((f, i) => i-8 >= 0 && (i - 8) % 5 == 0)
.map(p => p.trim())
}
console.log(result)
I have currently a script like this: (Which will run every minute and fetch any values)
// function 01
sheet2.getRange(sheet2.getLastRow() + 1, 1, 1, 6).setValues(values);
// function 02
sheet2.getRange(sheet2.getLastRow() + 1, 10, 1, 6).setValues(values);
It finds the last row and set the values in next row. Both are in separate functions. But currently it outputs something like this.
Current Output : NOT GOOD
// function 1 output here // function 2 output here
------------------------------------------------------------
| A | B | C || | | |
------------------------------------------------------------
| | | || D | E | F |
------------------------------------------------------------
| | | || G | H | I |
------------------------------------------------------------
| J | K | L || | | |
------------------------------------------------------------
I want that to be displayed like this:
EXPECTED RESULT
------------------------------------------------------------
| A | B | C || D | E | F |
------------------------------------------------------------
| J | K | L || G | H | I |
------------------------------------------------------------
| | | || | | |
------------------------------------------------------------
Hope I'm clear.
Try the below function, very slightly modified to pass the column from the solution Mogsdad supplied on Nov 27, 2014 for the New Sheets in response to the thread Faster way to find the first empty row
// Don's array approach - checks first column only
// With added stopping condition & correct result.
// From answer https://stackoverflow.com/a/9102463/1677912
// Added the passing of myColumn which needs to be a column range
// example use: var emptyRow = getFirstEmptyRowByColumnArray('B:B');
function getFirstEmptyRowByColumnArray(myColumn) {
var spr = SpreadsheetApp.getActiveSpreadsheet();
var column = spr.getRange(myColumn);
var values = column.getValues(); // get all data in one call
var ct = 0;
while ( values[ct] && values[ct][0] != "" ) {
ct++;
}
return (ct+1);
}
It could, of course, be written instead to just pass the column and create the range if you like.