Skip to content

Commit 6cc1df1

Browse files
committed
ref: refactor anagram
1 parent 274ca13 commit 6cc1df1

File tree

1 file changed

+91
-17
lines changed

1 file changed

+91
-17
lines changed

src/string/anagram.rs

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,101 @@
1-
pub fn check_anagram(s: &str, t: &str) -> bool {
2-
sort_string(s) == sort_string(t)
1+
use std::collections::HashMap;
2+
3+
/// Custom error type representing an invalid character found in the input.
4+
#[derive(Debug, PartialEq)]
5+
pub enum AnagramError {
6+
NonAlphabeticCharacter,
37
}
48

5-
fn sort_string(s: &str) -> Vec<char> {
6-
let mut res: Vec<char> = s.to_ascii_lowercase().chars().collect::<Vec<_>>();
7-
res.sort_unstable();
8-
res
9+
/// Checks if two strings are anagrams, ignoring spaces and case sensitivity.
10+
///
11+
/// # Arguments
12+
///
13+
/// * `s` - First input string.
14+
/// * `t` - Second input string.
15+
///
16+
/// # Returns
17+
///
18+
/// * `Ok(true)` if the strings are anagrams.
19+
/// * `Ok(false)` if the strings are not anagrams.
20+
/// * `Err(AnagramError)` if either string contains non-alphabetic characters.
21+
pub fn check_anagram(s: &str, t: &str) -> Result<bool, AnagramError> {
22+
let s_cleaned = clean_string(s)?;
23+
let t_cleaned = clean_string(t)?;
24+
25+
Ok(char_frequency(&s_cleaned) == char_frequency(&t_cleaned))
26+
}
27+
28+
/// Cleans the input string by removing spaces and converting to lowercase.
29+
/// Returns an error if any non-alphabetic character is found.
30+
///
31+
/// # Arguments
32+
///
33+
/// * `s` - Input string to clean.
34+
///
35+
/// # Returns
36+
///
37+
/// * `Ok(String)` containing the cleaned string (no spaces, lowercase).
38+
/// * `Err(AnagramError)` if the string contains non-alphabetic characters.
39+
fn clean_string(s: &str) -> Result<String, AnagramError> {
40+
s.chars()
41+
.filter(|c| !c.is_whitespace())
42+
.map(|c| {
43+
if c.is_alphabetic() {
44+
Ok(c.to_ascii_lowercase())
45+
} else {
46+
Err(AnagramError::NonAlphabeticCharacter)
47+
}
48+
})
49+
.collect()
50+
}
51+
52+
/// Computes the frequency of characters in a string.
53+
///
54+
/// # Arguments
55+
///
56+
/// * `s` - Input string.
57+
///
58+
/// # Returns
59+
///
60+
/// * A `HashMap` where the keys are characters and values are their frequencies.
61+
fn char_frequency(s: &str) -> HashMap<char, usize> {
62+
let mut freq = HashMap::new();
63+
for c in s.chars() {
64+
*freq.entry(c).or_insert(0) += 1;
65+
}
66+
freq
967
}
1068

1169
#[cfg(test)]
1270
mod tests {
1371
use super::*;
1472

15-
#[test]
16-
fn test_check_anagram() {
17-
assert!(check_anagram("", ""));
18-
assert!(check_anagram("A", "a"));
19-
assert!(check_anagram("anagram", "nagaram"));
20-
assert!(check_anagram("abcde", "edcba"));
21-
assert!(check_anagram("sIlEnT", "LiStEn"));
22-
23-
assert!(!check_anagram("", "z"));
24-
assert!(!check_anagram("a", "z"));
25-
assert!(!check_anagram("rat", "car"));
73+
macro_rules! test_cases {
74+
($($name:ident: $test_case:expr,)*) => {
75+
$(
76+
#[test]
77+
fn $name() {
78+
let (s, t, expected) = $test_case;
79+
assert_eq!(check_anagram(s, t), expected);
80+
assert_eq!(check_anagram(t, s), expected);
81+
}
82+
)*
83+
}
84+
}
85+
86+
test_cases! {
87+
empty_strings: ("", "", Ok(true)),
88+
empty_and_non_empty: ("", "Ted Morgan", Ok(false)),
89+
single_char_same: ("z", "Z", Ok(true)),
90+
single_char_diff: ("g", "h", Ok(false)),
91+
valid_anagram_lowercase: ("cheater", "teacher", Ok(true)),
92+
valid_anagram_with_spaces: ("Madam Curie", "Radium came", Ok(true)),
93+
valid_anagram_mixed_cases: ("Satan", "Santa", Ok(true)),
94+
valid_anagram_awesome: ("Anna Madrigal", "A man and a girl", Ok(true)),
95+
non_anagram: ("rat", "car", Ok(false)),
96+
invalid_anagram_with_special_char: ("hello!", "world", Err(AnagramError::NonAlphabeticCharacter)),
97+
invalid_anagram_with_numeric_chars: ("test123", "321test", Err(AnagramError::NonAlphabeticCharacter)),
98+
invalid_anagram_with_symbols: ("check@anagram", "check@nagaram", Err(AnagramError::NonAlphabeticCharacter)),
99+
non_anagram_length_mismatch: ("abc", "abcd", Ok(false)),
26100
}
27101
}

0 commit comments

Comments
 (0)