Forum Discussion
A LAMBDA Word Search Puzzle
- Jul 16, 2022
Here is one more variant
//------ variant without TEXTJOIN() reverseColumns= LAMBDA( data, LET( n, COLUMNS( data ), CHOOSECOLS( data, SEQUENCE(n,,n,-1) ) )); reversedText= LAMBDA( str, LET( head, LEFT(str), tail, RIGHT(str, LEN(str) - 1), IF(str = "", "", reversedText(tail) & head) )); isPolindrom= LAMBDA( text, text = reversedText( text ) ); checkSingleWord= LAMBDA( str, vector, LET( getWord, REDUCE("", vector, LAMBDA( a,v, IF( LEFT(str, LEN(a&v)) = a&v, a&v, IF( LEFT(str) = a, v, IF( a = str, a, "" ) ) ) ) ), IF( getWord = str, str, "") )); checkListOfWords= LAMBDA( wordsVector, vector, LET( getWords, REDUCE("", wordsVector, LAMBDA(a,v, VSTACK(a, checkSingleWord( v, vector) ) ) ), IFERROR( FILTER( getWords, getWords <> ""), "" ) )); wordsInMatrix= LAMBDA( data, wordsVector, LET( k, SEQUENCE( ROWS(data) ), scanData, REDUCE(1, k, LAMBDA(a,v, CHOOSECOLS( IF( v < SEQUENCE(,v,v,-1), a, VSTACK(a, checkListOfWords( Words, CHOOSEROWS(data,v) ) ) ), 1 ) )), removeFirst, DROP( scanData, 1 ), FILTER( removeFirst, removeFirst <> "") )); wordsInPuzzle= LAMBDA( data, wordsVector, LET( allWords, SORT( VSTACK( wordsInMatrix( data, wordsVector ), wordsInMatrix( reverseColumns( data ), wordsVector ), wordsInMatrix( TRANSPOSE( data ), wordsVector ), wordsInMatrix( reverseColumns( TRANSPOSE( data ) ), wordsVector ) )), ifPolindroms, MAP(allWords, LAMBDA(v, isPolindrom(v) ) ), polindroms, UNIQUE( FILTER(allWords, ifPolindroms)), notPolindroms, FILTER(allWords, ifPolindroms -1), stack, IF( ISERR(polindroms), notPolindroms, VSTACK( polindroms, notPolindroms ) ), SORT( stack ) ));
Congratulations on what you have achieved to date. The coding looks neater than I might have expected. I don't know how long it took you to code the method but it will take a while to unravel the approach.
Until such time, some thoughts on SCAN. Given a 2D array to scan, the function works through the entire 2D array row by row, so a strategy that works on one row could work over the entire range. There is a catch, in that some apparent matches might appear due to the string wrapping round rows. To avoid that, one could insert a column of blanks using HSTACK and then apply SCAN. Something similar can be achieved with the latest batch of array shaping functions such as TOCOL.
A different approach would be to use CONCAT to reduce the entire puzzle to a single string and exploit text searches within the Lambda functions. Such a strategy probably works best when there is only a single occurrence of a word to find. In each case, the transposing and reversing of strings is needed.
I will try to take another look and your workbook later.
- Patrick2788Jul 14, 2022Silver Contributor
Thank you for your reply. I spent a couple days on it on and off then dropped it for a few days because I couldn't resolve it with SCAN. I did go through the paces with TOCOL and reducing the letters to a scalar. I didn't feel good about where I was headed. I revisited the task when I thought of how the new Text functions may be helpful by using delimiters, so I played with feeding TEXTSPLIT/TEXTBEFORE/TEXTAFTER a stack of words to delimit on. SergeiBaklan - I need to take some time to study this solution. I've been looking at this puzzle too much lately but will come back to it soon.
The part I couldn't get around with SCAN was achieving something like this (A sample of the first two rows done manually):
The closest I came was getting WAVE and AES (placed in row 2) but the rest that followed was not accurate.
- SergeiBaklanJul 16, 2022Diamond Contributor
Here is one more variant
//------ variant without TEXTJOIN() reverseColumns= LAMBDA( data, LET( n, COLUMNS( data ), CHOOSECOLS( data, SEQUENCE(n,,n,-1) ) )); reversedText= LAMBDA( str, LET( head, LEFT(str), tail, RIGHT(str, LEN(str) - 1), IF(str = "", "", reversedText(tail) & head) )); isPolindrom= LAMBDA( text, text = reversedText( text ) ); checkSingleWord= LAMBDA( str, vector, LET( getWord, REDUCE("", vector, LAMBDA( a,v, IF( LEFT(str, LEN(a&v)) = a&v, a&v, IF( LEFT(str) = a, v, IF( a = str, a, "" ) ) ) ) ), IF( getWord = str, str, "") )); checkListOfWords= LAMBDA( wordsVector, vector, LET( getWords, REDUCE("", wordsVector, LAMBDA(a,v, VSTACK(a, checkSingleWord( v, vector) ) ) ), IFERROR( FILTER( getWords, getWords <> ""), "" ) )); wordsInMatrix= LAMBDA( data, wordsVector, LET( k, SEQUENCE( ROWS(data) ), scanData, REDUCE(1, k, LAMBDA(a,v, CHOOSECOLS( IF( v < SEQUENCE(,v,v,-1), a, VSTACK(a, checkListOfWords( Words, CHOOSEROWS(data,v) ) ) ), 1 ) )), removeFirst, DROP( scanData, 1 ), FILTER( removeFirst, removeFirst <> "") )); wordsInPuzzle= LAMBDA( data, wordsVector, LET( allWords, SORT( VSTACK( wordsInMatrix( data, wordsVector ), wordsInMatrix( reverseColumns( data ), wordsVector ), wordsInMatrix( TRANSPOSE( data ), wordsVector ), wordsInMatrix( reverseColumns( TRANSPOSE( data ) ), wordsVector ) )), ifPolindroms, MAP(allWords, LAMBDA(v, isPolindrom(v) ) ), polindroms, UNIQUE( FILTER(allWords, ifPolindroms)), notPolindroms, FILTER(allWords, ifPolindroms -1), stack, IF( ISERR(polindroms), notPolindroms, VSTACK( polindroms, notPolindroms ) ), SORT( stack ) ));
- Patrick2788Jul 19, 2022Silver Contributor
I'm wondering if it's possible (or even sensible) to use recursion with SCAN to check an element in the array to see if it contains a word from the word list when the element LEN is at least 3. The word would be returned and the excess letters would be discarded. I'm messing around with recursion and SUBSTITUTE and receiving memory errors.
Ideally, the SCAN results would be like this: