Skip to content

Commit

Permalink
Merge pull request #49 from apraga/search-diseases-by-name
Browse files Browse the repository at this point in the history
Searching OMIM disease by name (partial match)
  • Loading branch information
anergictcell authored Mar 20, 2024
2 parents 230abc7 + f79f40c commit b1c08ff
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
12 changes: 12 additions & 0 deletions examples/search_by_name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Prints every term and its associated genes
use hpo::Ontology;

fn main() {
let ontology = Ontology::from_binary("tests/ontology.hpo").unwrap();
let cystinosis = ontology.disease_by_name("Cystinosis").unwrap();
println!("first match: {:?}", cystinosis.name());
for result in ontology.diseases_by_name("Cystinosis") {
println!("{:?}", result.name());
}
}
82 changes: 82 additions & 0 deletions src/ontology.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use core::fmt::Debug;
use std::collections::hash_map::Values;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Read;
use std::iter::Filter;
use std::ops::BitOr;
use std::path::Path;

Expand Down Expand Up @@ -320,6 +322,17 @@ impl Debug for Ontology {
}
}

pub struct DiseaseIter<'a, F> {
inner: Filter<Values<'a, OmimDiseaseId, OmimDisease>, F>,
}

impl<'a, F: FnMut(&&'a OmimDisease) -> bool + 'a> Iterator for DiseaseIter<'a, F> {
type Item = &'a OmimDisease;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}

/// Public API of the Ontology
///
/// Those methods are all safe to use
Expand Down Expand Up @@ -745,6 +758,50 @@ impl Ontology {
self.omim_diseases.values()
}

/// Returns an Iterator of all [`OmimDisease`]s whose names contains the provided
/// substring.
///
/// # Examples
///
/// ```
/// use hpo::Ontology;
/// let ontology = Ontology::from_binary("tests/example.hpo").unwrap();
///
/// for result in ontology.diseases_by_name("Cystinosis") {
/// println!("{:?}", result.name());
/// }
/// ```
pub fn diseases_by_name<'a>(
&'a self,
substring: &'a str,
) -> DiseaseIter<impl FnMut(&&'a OmimDisease) -> bool + 'a> {
DiseaseIter {
inner: self
.omim_diseases
.values()
.filter(move |disease| disease.name().contains(substring)),
}
}

/// Returns the first matching [`OmimDisease`] whose name contains the provided
/// substring.
///
/// If no such substring is present, return `None`.
///
/// # Examples
///
/// ```
/// use hpo::Ontology;
/// let ontology = Ontology::from_binary("tests/example.hpo").unwrap();
///
/// let cystinosis = ontology.disease_by_name("Cystinosis");
/// ```
pub fn disease_by_name(&self, substring: &str) -> Option<&OmimDisease> {
self.omim_diseases
.values()
.find(|&disease| disease.name().contains(substring))
}

/// Returns the Jax-Ontology release version
///
/// e.g. `2023-03-13`
Expand Down Expand Up @@ -1754,4 +1811,29 @@ mod test {
assert_eq!(diff.removed_omim_diseases().len(), 0);
assert_eq!(diff.changed_omim_diseases().len(), 0);
}

#[test]
fn diseases_by_name() {
let ont = Ontology::from_binary("tests/example.hpo").unwrap();
assert_eq!(ont.diseases_by_name("Cystinosis").count(), 3);
assert_eq!(ont.diseases_by_name("Macdermot-Winter syndrome").count(), 1);
assert_eq!(ont.diseases_by_name("anergictcell syndrome").count(), 0);

let cystinosis = vec![
"Cystinosis, adult nonnephropathic",
"Cystinosis, late-onset juvenile or adolescent nephropathic",
"Cystinosis, nephropathic",
];
assert_eq!(
cystinosis.contains(&ont.disease_by_name("Cystinosis").unwrap().name()),
true
);
assert_eq!(
ont.disease_by_name("Macdermot-Winter syndrome")
.unwrap()
.name(),
"Macdermot-Winter syndrome"
);
assert_eq!(ont.disease_by_name("anergictcell syndrome").is_none(), true);
}
}

0 comments on commit b1c08ff

Please sign in to comment.