24
votes
Programming Challenge: Anagram checking.
It's been over a week since the last programming challenge and the previous one was a bit more difficult, so let's do something easier and more accessible to newer programmers in particular. Write a function that takes two strings as input and returns true
if they're anagrams of each other, or false
if they're not.
Extra credit tasks:
- Don't consider the strings anagrams if they're the same barring punctuation.
- Write an efficient implementation (in terms of time and/or space complexity).
- Minimize your use of built-in functions and methods to bare essentials.
- Write the worst--but still working--implementation that you can conceive of.
Haskell is pretty cool :)
That is beautifully concise.
This was fun! I'm doing this one in go. I'm fairly new to go, so if I'm making any obvious mistakes feel free to point them out :)
Edited with /u/Emerald_Knight's findings.
Almost! Consider the following test case:
These should evaluate as being anagrams, but don't :)
You're right! I completely forgot about letter casing. I've edited the comment :)
Ah, right, I think there's also a problem with punctuation. I forgot to bring that up. Anagrams should generally be punctuation-agnostic :)
A C solution that counts characters:
Very nice! But it doesn't work with Unicode :-p
Yeah, that's a much harder problem. In Turkish, for example, "William Shakespeare" is not an anagram for "I am a weakish speller" because the lowercase version of "I" is "ı", not "i".
Yeah, I give a pass on unicode because then you need to have localization awareness in order to maintain accuracy, and that's beyond the scope of a quick programming challenge and begins to dive into a full-blown project that could take a very long time to get right, and even then you're likely to miss some edge cases. ASCII is sufficient for the purposes of this challenge :)
A very space-efficient array version. I like the zero-offset check!
I have never seen that for loop syntax with pointers before. Googling it gives a lot of results with char arrays, but can it be generalized to other types of arrays?
Yes! The same syntax works for any array that ends with a zero. It's common for char arrays because strings in C are represented by char arrays ending in a zero byte (by convention).
Ah okay, so if I were to use it on a numeric array I would need to ensure that it has a terminating 0. I'll have to play with that a bit. Thanks!
I always feel icky writing functions like this that work on specifically two inputs. So I've generalized the code to work with 0 or more strings (providing 0 or 1 string will always result in a
True
return value).Edit:
O(n * m)
runtime! :D (where the average word length isn
and there arem
words).Different amounts of white space or punctuation will cause the check to fail. I'm liking the variable-length parameters, though!
Also, I remember you from the first programming challenge I posted! Good to see you here again :)
Given that the argument is
words
and notstrings
, in my world the programmer should handle that before passing in values :PRelying on the user to properly strip non-alpha characters? I, too, like to live dangerously ;)
Rust
I've only just started learning Rust and have only coded as a hobby. How'd I do?
Edit:
cargo bench
puts it at 572 ns/iter (+/- 11) to run the function anagram():Your solution doesn't appear to account for punctuation. That being said, your solution otherwise appears correct to my non-Rusted eyes :)
Change !c.is_whitespace() to c.is_alphabetic() for any alphabetic character, or otherwise c.is_digit(36) for any 0-9 A-z.
Yeah, that sounds like it would do it!
I decided to modify it to work with more than two strings, the function requiring a vector of strings instead. It is however slightly slower for two strings.
Late, but here's a pure Bash 4+ solution:
As for me, I've had a long week starting at my new job, so I'm going to keep my solution simple this time:
Just out of curiosity, why is PHP your language of choice for programming challenges?
It just happens to be the language I work with professionally at present. Since it's the one I use the most, it's naturally the one I'll turn to when writing up a quick solution to something. Additionally, me being a web programming makes JavaScript the second most frequently used language for me.
That being said, it's not my favorite language. Personally, I have a bit of a fondness for Java, though I haven't touched it in quite a while. I've seen some other interesting languages around, too, but I tend not to dabble too much in new, shiny tools and languages very often. I'm very pragmatic and tend to grab tools as I need them or foresee myself needing them.
Great response, thanks. What do you enjoy about Java? I've found it a bit, too expressive(?) for my liking.
You probably mean verbose.
That's it, thanks.
I suppose to some extent I find the verbosity of the language to be acceptable in return for the flexibility it can provide, though at times it can be frustrating trying to fiddle with types. I haven't used it myself, but I imagine Kotlin would be more your cup of tea. I really should try it out sometime myself.
I wanted to try it without doing a sort, so here's a questionably-readable solution in JavaScript (ES6) that compares the strings by counting instances of each character.
Quick tests:
Interesting solution! You really took advantage of JavaScript's feature set. Nicely done :)
Julia version, it might be possible to do a non-allocating version, but I'm not sure how.
I don't think your solution accounts for varying punctuation, even whitespace. Julia seems like an interesting language, though, and your solution seems correct otherwise. I'm glad to be seeing languages in here that I'm not familiar with :)
Yeah I would need some filter after the split. Julia is awesome, you can write functional-like stuff like that, vectorized, or C-like loops and you basically get the same near-optimal performance. It's better for numerical/scientific computing rather than string processing though.
I've made version without any sorting, so I think, I might have one of the fastest versions here. Time complexity is linear, memory complexity is constant.
I've used python, which I've started with few days ago.
Edit: Added syntax highlighting
Unfortunately this doesn't work when letters are repeated:
Thank you, this doesn't work when the strings do not have equal length. I've edited it.
Unfortunately I can still break it, if I'm not mistaken:
I don't think it's possible to fix it.
Hm... I think you are right. The problem is with multiple characters.
I've wanted to follow Flag logic:
And you can combine the states:
The problem is with multiple letters. I think you are right, this problem can be solved without sorting only by counting letters.
Exactly, it's the principle of binary numeration, but that decomposition is only unique when each digit is unique.
For the sake of providing an explanation to less experienced readers:
The submitted solution was trying to take advantage of a property of adding powers of 2 that is often used in what are called "bitmasks", a tool I highly recommend reading up on. The idea is basically that you can tell whether or not something exists by examining a specific bit in the mask.
The problem is that this only works for existence checking. The reason is because if you add together two identical powers of 2 in the form 2n + 2n, then you get 2n + 2n = 2 x 2n = 2n+1. Thus, the string "ff" will appear equal to "g", for example.
You are right, I should use loops, but it was only for me to test if it is working correctly, plus in vim, it's often faster to do it this dumb way instead of loops.
But you're right, I'll change it.
Figured I'd try something stupid and convoluted, so I came up with the idea to create two temporary directories, inside which, create a file for each letter in each word, then simply compare the two directories.
By the time I finished I realized the flaw of course is that it doesn't account for repeating characters. "foo" and "oooooooooof" are considered anagrams. Oh well. And of course this has numerous other problems as well. Can't deal with spaces or a lot of punctuation. Probably exploitable by directory traversal attacks etc.
It may be a non-working solution, but I love the ingenuity! I'm sure that with some modifications, this could be a perfectly horrible implementation :)
Alright, well such a thing clearly shouldn't exist, but after smoking a jazz cigarette and a bit of introspection, you've inspired me to finish what I started.
Now it handles duplicate letters just fine. Handles mixed case, handles strings with spaces (though spaces are ignored).
Still has glaring issues if you try using any special characters such as ! or / or & you'll end up with wildly unexpected results.
Now I think I need a long shower and to think about what I'm doing with my life.
This is simultaneously beautiful and horrifying. Bravo.
Thanks! Just following the UNIX "everything is a file" philosophy to its logical end.
still in my kotlin comfort zone, heavily leaning on the stdlib
It doesn't look like your solution would handle differing whitespace or punctuation. You may want to account for that.
That aside, it looks like you're using a very functional programming style. I haven't used Kotlin myself, so I wasn't aware that this was supported by the language!
I wanted to try my hand at this. I did something a little different, since the most reasonable approach I can think of in C appears to be here already. lazyGram does a few checks that should work in almost all cases, but it's probably still possible to confuse it and get a wrong result. That said, I haven't yet managed to mess it up yet, but maybe someone here can find a good test case.
Second time submitting a solution. Yuss!
In Python:
Saw this pop up and thought it was this week's. Oops! Posting anyways since I already did it. Did mine in ruby:
These challenges aren't meant to be restricted to the week in which they're posted. Please feel free to submit your own solutions to any challenges you want at any time :)
Don't have a laptop on me right now and I'm a newbie but I'd sort them(not sure if sort functions would work on a string, so I'd probably assaign numbers to letters) and then compare both arrays
Here’s some ugly, ugly bash: