You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

64 lines
1.8 KiB
Rust

use crate::error::XKCDResult;
use crate::get_archive;
use std::cmp::Ordering;
/// Searches for a comic containing the words from the query
pub async fn search(query: &str) -> XKCDResult<Vec<(String, u32)>> {
let archive = get_archive().await?;
let words: Vec<String> = query
.split(" ")
.into_iter()
.map(|s| s.to_lowercase())
.collect();
let mut entries: Vec<(usize, String, u32)> = archive
.into_iter()
.filter_map(|(key, id)| {
let score = words
.iter()
.filter(|w| key.to_lowercase().contains(*w))
.count();
if score <= 0 {
None
} else {
Some((score, key, id))
}
})
.collect();
entries.sort_by_key(|(s, _, _)| *s);
entries.reverse();
Ok(entries
.into_iter()
.map(|(_, title, id)| (title, id))
.collect())
}
/// Searches for a comic with a fuzzy compare function that assigns a score
/// to each match.
/// The Threshold defines what still counts as a match
pub async fn search_fuzzy(query: &str, threshold: f32) -> XKCDResult<Vec<(String, u32)>> {
let archive = get_archive().await?;
let query = query.to_lowercase();
let mut entries: Vec<(f32, String, u32)> = archive
.into_iter()
.map(|(key, id)| (trigram::similarity(&query, &key.to_lowercase()), key, id))
.filter(|(score, _, _)| score >= &threshold)
.collect();
entries.sort_by(|(s1, _, _), (s2, _, _)| {
if s1 > s2 {
Ordering::Greater
} else if s1 < s2 {
Ordering::Less
} else {
Ordering::Equal
}
});
entries.reverse();
Ok(entries
.into_iter()
.map(|(_, title, id)| (title, id))
.collect())
}