Check whether two strings are anagrams

Inspired by Monday's Reddit daily programmer challenge, I wrote a function to check whether two strings are anagrams. It doesn't take the same input as the challenge, though, since I don't want to handle user input (yet).

For the lazy ones, the task is to write a function that checks whether the letters in the first word can be shuffled (and upcased/downcased) to create the second word. Punctuation and whitespace isn't important.

This is more or less the first code I've written in Rust, so any kind of feedback is welcome:

/// Returns the sorted alphabetic symbols of a string in lowercase.
fn normalize(s : &str) -> Vec<char> {
let mut characters : Vec<char> = s.to_lowercase()
.chars()
.filter(|x| x.is_alphabetic())
.collect();
characters.sort();
characters
}

/// Returns true if the sets of alphabetic symbols coincide.
pub fn is_anagram(a : &str, b : &str) -> bool{
normalize(a) == normalize(b)
}

#[test]
fn is_anagram_test() {
assert!( is_anagram("Clint Eastwood","Old West Action"));
assert!( is_anagram("wisdom","mid sow"));
assert!(!is_anagram("Reddit","Eat Dirt"));
assert!( is_anagram("Schoolmaster","The classroom"));
assert!( is_anagram("Vacation Times", "I'm Not as Active"));
assert!( is_anagram("12431b53c11a5324", "abc"));
}


I'm not particularly fond of using a mut Vec<char> just to use sort, but I guess it's the same situation as in C++, where std::sort will also modify a container in-place. The code was written with previous experience in C++, but with the following Haskell code in mind:

isAnagramOf :: String -> String -> Bool
isAnagramOf = (==) on (sort . map toLower . filter isLetter)

• I usually go with "What happens inside a function stays inside a function". There is no way to tell outside of normalize whether you used mutability or not. The function is pure, side effect free and re-entrant as it is. So why bother? Sep 14 '16 at 10:16
• @BitTickler: I don't hate it. I just was kind of surprised that there are so many functions for iterators, but not a .sorted() for cloneable things with a total order, so I thought I missed something. But as I said, it's the same in C++ either way.
– Zeta
Sep 14 '16 at 11:02

1. There is no space before : in types.

2. There is a space after the return type

3. There is a space between function arguments, after the comma.

4. str::to_lowercase allocates a new string. It's a potential optimization to iterate through each character and convert to lowercase. Profiling should be done if performance matters.

5. Could use itertools sorted to reduce some boilerplate. Does the same thing under the hood.

extern crate itertools;
use itertools::Itertools;

/// Returns the sorted alphabetic symbols of a string in lowercase.
fn normalize(s: &str) -> Vec<char> {
s.chars()
.flat_map(char::to_lowercase)
.filter(|c| c.is_alphabetic())
.sorted()
}

/// Returns true if the sets of alphabetic symbols coincide.
pub fn is_anagram(a: &str, b: &str) -> bool {
normalize(a) == normalize(b)
}

#[test]
fn is_anagram_test() {
assert!( is_anagram("Clint Eastwood", "Old West Action"));
assert!( is_anagram("wisdom", "mid sow"));
assert!(!is_anagram("Reddit", "Eat Dirt"));
assert!( is_anagram("Schoolmaster", "The classroom"));
assert!( is_anagram("Vacation Times", "I'm Not as Active"));
assert!( is_anagram("12431b53c11a5324", "abc"));
}


Ultimately, you won't be able to achieve the same particular kind of elegance as the Haskell solution, but I'd hope that the performance would be better.

• Do you have any source for the styling guidelines? Is there a linting program? Otherwise those are more or less primary opinion, if there isn't a "official" recommendation (see PEP8 in Python for example).
– Zeta
Sep 16 '16 at 6:23
• @Zeta rustfmt, also via the big "Format" button at the top of the official Playground. The style guide source. Sep 16 '16 at 13:54