More Java homework:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Public Function IsAnagram(ByVal sWordOne As String, ByVal sWordTwo As String) As Boolean Dim vaOne As Variant Dim vaTwo As Variant Dim bReturn As Boolean Dim i As Long Const sRPLC As String = "+" sWordOne = Replace(sWordOne, Space(1), vbNullString) sWordTwo = Replace(sWordTwo, Space(1), vbNullString) If Len(sWordOne) = Len(sWordTwo) Then For i = 1 To Len(sWordOne) sWordTwo = Replace(sWordTwo, Mid$(sWordOne, i, 1), sRPLC, 1, 1, vbTextCompare) Next i bReturn = sWordTwo = String(Len(sWordOne), sRPLC) Else bReturn = False End If IsAnagram = bReturn End Function |
First, I remove all the spaces. Then I make sure the two words are the same length. Then I loop through all the letters in the first word, find them in the second word, and replace them with a plus sign. If the second word is all plus signs at the end, then it’s an anagram. My first thought was to put the letters in an array and sort them, but that’s too much looping.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Public Function IsPalindrome(ByVal sPhrase As String) Dim i As Long Dim bReturn As Boolean bReturn = True sPhrase = Replace(sPhrase, Space(1), vbNullString) For i = 1 To Len(sPhrase) If LCase(Mid$(sPhrase, i, 1)) <> LCase(Mid$(sPhrase, Len(sPhrase) + 1 - i, 1)) Then bReturn = False Exit For End If Next i IsPalindrome = bReturn End Function |
Nothing too fancy here. Again, I remove all the spaces. Then I compare the first letter to the last letter, the second letter to the penultimate letter, and so on. If there’s every not a match, set the return value to False and quit looking.
If the Boy (yoB) likes palindromes he should love Weird Al Jankovic’s son Bob (boB):
https://newtonexcelbach.wordpress.com/2015/05/10/avoid-si-aibohphobia-is-di-ova/
I had a go at a palindrome UDF as well (in VBA and Python):
https://newtonexcelbach.wordpress.com/2015/05/31/reversing-bob/
Why not ?
And
What about some mind blowing formulas to identify anagrans/palindromes?
http://excelxor.com/2014/08/23/advanced-formula-challenge-2-identifying-anagrams/
Results and discussion here: http://excelxor.com/2014/08/30/advanced-formula-challenge-2-results-and-discussion/
@snb,
As written, your F_ana_snb function has a flaw… it considers “abcde” and “a” to be anagrams of each other (extra letters in the first argument not appearing in the second argument are ignored).
Just to follow up on my previous message, I think the following modification to snb’s anagram function will make it work correctly…
Function F_ana_snb(c00, c01)
For j = 1 To Len(c00)
If InStr(c01, Mid(c00, j, 1)) Then
c01 = Replace(c01, Mid(c00, j, 1), “”, , 1, 1)
Mid(c00, j) = ” ”
End If
Next
F_ana_snb = Trim(c01) = Trim(c00)
End Function
@Rick
Quite right !
@snb,
Does that function actually work for you? I seem to be getting 0 returned from it no matter what the two arguments are.
@Rick
Now it does:
Here is a one-liner, albeit an extremely long one, in which I used line continuation characters in order to (hopefully) layout neatly in the code display box for this blog’s comment box (you can remove the line continuation characters after copy/pasting it into VBA module if you want to see it as a physical one-liner)…
Hmm! I see all the ampersand characters in the code I just posted became “&” in the code listing… did I do something wrong? Is there a way to post the code so that the ampersands remain as ampersands?
Just waiting snb says that Rick’s last code is very easy to read lol
Here’s my ugly palindrome formula:
=SUMPRODUCT(N(MID(SUBSTITUTE(A1,” “,””),LEN(SUBSTITUTE(A1,” “,””))+1-ROW(INDIRECT(“1:”&LEN(SUBSTITUTE(A1,” “,””)))),1)=MID(SUBSTITUTE(A1,” “,””),ROW(INDIRECT(“1:”&LEN(SUBSTITUTE(A1,” “,””)))),1)))=LEN(SUBSTITUTE(A1,” “,””))
Anagram in formula-form:
=PRODUCT(FREQUENCY(CODE(MID(SUBSTITUTE(B1;” “;””);ROW(OFFSET(B$1;;;LEN(SUBSTITUTE(B1;” “;””))));1));100))=PRODUCT(FREQUENCY(CODE(MID(SUBSTITUTE(B1;” “;””);ROW(OFFSET(B$1;;;LEN(SUBSTITUTE(B1;” “;””))));1));100))
@snb,
I don’t think that formula works all the time. For example, it reports TRUE if A1 equals “my bad” and B1 equals “am bad”.
Here is my attempt which appears to work correctly… it is an array-entered** formula,
=AND(IFERROR(TRANSPOSE(CHAR(SMALL(CODE(MID(SUBSTITUTE(A1,” “,””),ROW(INDIRECT(“1:”&LEN(SUBSTITUTE(A1,” “,””)))),1)),ROW(INDIRECT(“1:”&LEN(SUBSTITUTE(A1,” “,””)))))))=TRANSPOSE(CHAR(SMALL(CODE(MID(SUBSTITUTE(B1,” “,””),ROW(INDIRECT(“1:”&LEN(SUBSTITUTE(B1,” “,””)))),1)),ROW(INDIRECT(“1:”&LEN(SUBSTITUTE(B1,” “,””))))))),””))
**Commit this formula using CTRL+SHIFT+ENTER and not just Enter by itself
Let’s try that again, this time putting the formula inside code tags to see if the quote marks remain as normal quote marks this time…
Remember to array-enter the formula (CTRL+SHIFT+ENTER and not Enter by itself)
Well, that attempt screwed up the ampersands.
Does anyone know of a way to enter code and/or formulas where the quote marks remain as “normal” quote marks and the ampersand does not get posted with that extra text???
From this SO post, stackoverflow.com/questions/1115001/write-a-function-that-returns-the-longest-palindrome-in-a-given-string, code to find the longest palindrome in a string
@Rick. The plugin I use to code color comments doesn’t work right. It’s nothing you’re doing, it just a crappy plugin that I haven’t replaced yet.
Is Palindrome is too easy: the native VBA.Strings.ReverseString spoils the fun:
However, your algorithm for detecting anagrams is surprisingly efficient: I looked for ways of using the Byte Array / String type identity, and there’s nothing except a crude Byte Sum check as a second test to eliminate anything that passed the len() comparison.
You can’t do a simple sort-and-string-compare of the byte arrays, because there are two-byte encoded unicodes that would sort as combinations of Latin ‘ASCII’ chars that only use a single byte.
A native Sort() function for arrays would make it worth your while to turn the cleaned-up strings into arrays of chars, but we don’t have that; and I agree that you’re right not to bother with the complexity of a hand-rolled sort.
CountIf would be nice if we had it for VBA arrays instead of ranges, but we don’t… But we do have an obscure VBA.Strings function which does the same thing, and it’s an interesting alternative.
Note that the only possible source of performance improvement is that we don’t grind our way to the bitter end and return a final comparison: the first failed character count bails out with
:
On a more general note, VBA.Strings.Filter() deserves to be better known: if you’re smart the Split() function, it’s a useful counting and comparison tool.
Looks like the cc-vb codes eat < and > characters.
You might want to check these two lines in my code:
And here, another ‘not equals’ comparison: