use rand::prelude::*; use std::collections::HashMap; use std::fmt::{Display, Formatter, Error}; pub struct Seq<'a> { alphabet: Vec<&'a str>, distr: rand::distributions::Uniform, pos_distr: rand::distributions::Uniform, seq: Vec<&'a str>, } impl Display for Seq<'_> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { let pretty: String = self.seq .iter() .enumerate() .map(|(i, nt)| if (i + 1) % 60 == 0 { format!("{}\n", nt) } else { nt.to_string() }) .collect(); let counts_hm = self.seq .iter() .fold(HashMap::<&str, usize>::new(), |mut m, nt| { *m.entry(nt).or_default() += 1; m }); let mut counts_vec: Vec<(&str, usize)> = counts_hm.into_iter().collect(); counts_vec.sort_by(|a, b| a.0.cmp(&b.0)); let counts_string = counts_vec .iter() .fold(String::new(), |mut counts_string, (nt, count)| { counts_string += &format!("{} = {}\n", nt, count); counts_string }); write!(f, "Seq:\n{}\n\nLength: {}\n\nCounts:\n{}", pretty, self.seq.len(), counts_string) } } impl Seq<'_> { pub fn new(alphabet: Vec<&str>, len: usize) -> Seq { let distr = rand::distributions::Uniform::new_inclusive(0, alphabet.len() - 1); let pos_distr = rand::distributions::Uniform::new_inclusive(0, len - 1); let seq: Vec<&str> = (0..len) .map(|_| { alphabet[thread_rng().sample(distr)] }) .collect(); Seq { alphabet, distr, pos_distr, seq } } pub fn insert(&mut self) { let pos = thread_rng().sample(self.pos_distr); let nt = self.alphabet[thread_rng().sample(self.distr)]; println!("Inserting {} at position {}", nt, pos); self.seq.insert(pos, nt); } pub fn delete(&mut self) { let pos = thread_rng().sample(self.pos_distr); println!("Deleting {} at position {}", self.seq[pos], pos); self.seq.remove(pos); } pub fn swap(&mut self) { let pos = thread_rng().sample(self.pos_distr); let cur_nt = self.seq[pos]; let new_nt = self.alphabet[thread_rng().sample(self.distr)]; println!("Replacing {} at position {} with {}", cur_nt, pos, new_nt); self.seq[pos] = new_nt; } } fn main() { let mut seq = Seq::new(vec!["A", "C", "T", "G"], 200); println!("Initial sequnce:\n{}", seq); let mut_distr = rand::distributions::Uniform::new_inclusive(0, 2); for _ in 0..10 { let mutation = thread_rng().sample(mut_distr); if mutation == 0 { seq.insert() } else if mutation == 1 { seq.delete() } else { seq.swap() } } println!("\nMutated sequence:\n{}", seq); }