use std::collections::HashMap;
pub struct SynonymMap {
entries: HashMap<String, Vec<String>>,
}
impl SynonymMap {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
}
}
pub fn add(&mut self, term: &str, synonyms: &[&str]) {
let key = term.to_lowercase();
let vals: Vec<String> = synonyms.iter().map(|s| s.to_lowercase()).collect();
self.entries.insert(key, vals);
}
pub fn expand(&self, tokens: &[String]) -> Vec<String> {
let mut expanded = Vec::with_capacity(tokens.len() * 2);
for token in tokens {
expanded.push(token.clone());
if let Some(synonyms) = self.entries.get(token.as_str()) {
expanded.extend(synonyms.iter().cloned());
}
}
expanded
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl Default for SynonymMap {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn synonym_expansion() {
let mut syn = SynonymMap::new();
syn.add("db", &["databas", "rdbms"]);
let tokens = vec!["db".to_string(), "query".to_string()];
let expanded = syn.expand(&tokens);
assert_eq!(expanded.len(), 4);
assert!(expanded.contains(&"databas".to_string()));
assert!(expanded.contains(&"rdbms".to_string()));
}
#[test]
fn empty_synonym_map() {
let syn = SynonymMap::new();
assert!(syn.is_empty());
assert_eq!(syn.len(), 0);
let tokens = vec!["hello".to_string()];
assert_eq!(syn.expand(&tokens), tokens);
}
}