Forum Discussion
LAMBDA Halloween Challenge
- Oct 30, 2022
Finally, I have a solution!
This time I used a Lambda function to add 1 to the previous index (stored in base n) but before returning the value, I scanned the digits and copied the larger digit across.
WorksheetFormula = LET( count, COUNTA(Items), initialise, REPT("0",pick), indices, VSTACK( initialise, SCAN(initialise, SEQUENCE(combinations-1), NextCombinationλ(count,pick)) ), INDEX(Items, 1 + Explodeλ(indices)) )
where
NextCombinationλ = LAMBDA(n,p, LAMBDA(initial,s, LET( place, n^SEQUENCE(1,p,p-1,-1), increment, 1 + SUM(place * Explodeλ(initial)), converted, BASE(increment,n,p), vector, Explodeλ(converted), modified, SCAN( , vector, Maxλ), CONCAT(modified) ) ) );
supported by
Explodeλ = LAMBDA(term, MID(term, SEQUENCE(1,pick), 1)); Maxλ = LAMBDA(u, v, Max(u,v));
I have just performed the calculation for 8 picks taken for 9 items in 300ms. Ther are 12,870 combinations and the permutations would have been over 43M!
Impressive! I'm still studying how you pulled this off. When I thought of this experiment several weeks ago, I began by studying the occurrences for each item in each column looking for patterns in the numbers.
This is the distribution of items in each column. There's some symmetry but probably not enough to go on that would top anything you've created. It's interesting that when UNIQUE is used on the above matrix, the occurrences for each number is 2 with the exception of 2 numbers appearing 4 times.
The key line is
modified, SCAN( , vector, Maxλ),
which scans a row of indices to ensure each sequence increases monotonically. That allows the algorithm to make massive strides forward to the next possible combination rather than simply incrementing through the permutations and testing the outturn.
- mtarlerOct 31, 2022Silver Contributor
PeterBartholomew1 Patrick2788 Ok so I will submit mine but I think it is very similar to Peter's (but I have some questions for him...):
=LET(b, COUNTA(Items), combN, COMBINA(b,pick), n, SEQUENCE(combN,,0), series, SCAN(,n,LAMBDA(p,i, CONCAT(SCAN(0, MID(BASE(DECIMAL(p,b)+1,b,pick),SEQUENCE(pick),1),LAMBDA(pp,ii,IF(pp>ii,pp,ii)))))), INDEX(Items,DECIMAL(MID(series,SEQUENCE(1,pick),1),b)+1))
Peter's is much more readable than mine but I still get lost. In mine I create a list of possible options using base() which is the same from what I can tell. I build my list by a manual sequential adding 1 and then make sure it isn't less then the index before it. In looking back it appears you guy originally did a filtering but I think this is how Peter's new version works also. My series is built on line 2 and proud to say this is the first time I found an advantage to doing a SCAN() without the initialize value to force it to use the first value in the sequence (zero in this case).
Since it is hard to read in the middle is BASE(DECIMAL()+1) which converts the text to a number, then +1 and back to the text. then outside that is a MID() to break it into characters and those characters are sent through the SCAN with the IF(>,,). I use the IF(>,,) instead of MAX because I don't bother converting back to decimal until the end so the IF can handle the ascii.
maybe peter can run the speed test on this and see how it compares.