Iterator Pattern

Exercises

Iterator trait

// Make the code compile by implementing the Iterator trait for `Queue`.

struct Queue {
    items: Vec<i32>,
}

impl Queue {
    fn new(items: Vec<i32>) -> Self {
        Self { items }
    }
}

impl Iterator for Queue {
    type Item;
    fn next(&mut self) -> Option<Self::Item> {}
}

fn main() {
    let mut queue = Queue::new(vec![3, 2, 1]);
    assert!(matches!(queue.next(), Some(3)));
    assert!(matches!(queue.next(), Some(2)));
    assert!(matches!(queue.next(), Some(1)));
    assert!(matches!(queue.next(), None));
}
Solution
struct Queue {
  items: Vec<i32>,
}

impl Queue {
  fn new(items: Vec<i32>) -> Self {
      Self { items }
  }
}

impl Iterator for Queue {
  type Item = i32;
  fn next(&mut self) -> Option<Self::Item> {
      if self.items.len() > 0 {
          Some(self.items.remove(0))
      } else {
          None
      }
  }
}

fn main() {
  let mut queue = Queue::new(vec![3, 2, 1]);
  assert!(matches!(queue.next(), Some(3)));
  assert!(matches!(queue.next(), Some(2)));
  assert!(matches!(queue.next(), Some(1)));
  assert!(matches!(queue.next(), None));
}

Into iterator 1

// Provide the trait implementations and make the code execute successfully.

struct Employee {
    first_name: String,
    last_name: String,
    id: String,
}

struct EmployeeIter {
    state: Vec<String>,
}

impl Iterator for EmployeeIter {
    type Item;
    fn next(&mut self) -> Option<Self::Item> {}
}

impl IntoIterator for Employee {
    type Item;
    type IntoIter;
    fn into_iter(self) -> Self::IntoIter {}
}

fn main() {
    let employee = Employee {
        first_name: "Alice".to_owned(),
        last_name: "Smith".to_owned(),
        id: "ab123".to_owned(),
    };
    let mut emp_iter = employee.into_iter();
    println!("First name: {}", emp_iter.next().unwrap());
    println!("Last name: {}", emp_iter.next().unwrap());
    println!("ID: {}", emp_iter.next().unwrap());
    assert_eq!(emp_iter.next(), None);
}
Solution
struct Employee {
  first_name: String,
  last_name: String,
  id: String,
}

struct EmployeeIter {
  state: Vec<String>,
}

impl Iterator for EmployeeIter {
  type Item = String;
  fn next(&mut self) -> Option<Self::Item> {
      self.state.pop()
  }
}

impl IntoIterator for Employee {
  type Item = String;
  type IntoIter = EmployeeIter;
  fn into_iter(self) -> Self::IntoIter {
      EmployeeIter {
          state: vec![
              self.id,
              self.last_name,
              self.first_name,
          ]
      }
  }
}

fn main() {
  let employee = Employee {
      first_name: "Alice".to_owned(),
      last_name: "Smith".to_owned(),
      id: "ab123".to_owned(),
  };
  let mut emp_iter = employee.into_iter();
  println!("First name: {}", emp_iter.next().unwrap());
  println!("Last name: {}", emp_iter.next().unwrap());
  println!("ID: {}", emp_iter.next().unwrap());
  assert_eq!(emp_iter.next(), None);
}

Into iterator 2

// Fix the code by completing the into_iter() method.

struct Employee {
    first_name: String,
    last_name: String,
    id: String,
}

impl IntoIterator for Employee {
    type Item = String;
    type IntoIter = std::vec::IntoIter<String>;
    fn into_iter(self) -> Self::IntoIter {
        vec![
            format!("First name: {}", self.first_name),
            // do the same for last_name & id
        ]
    }
}

fn main() {
    let employee = Employee {
        first_name: "Alice".to_owned(),
        last_name: "Smith".to_owned(),
        id: "ab123".to_owned(),
    };
    println!("Employee Details:");
    for detail in employee {
        println!("{detail}");
    }
}
Solution
struct Employee {
  first_name: String,
  last_name: String,
  id: String,
}

impl IntoIterator for Employee {
  type Item = String;
  type IntoIter = std::vec::IntoIter<String>;
  fn into_iter(self) -> Self::IntoIter {
      vec![
          format!("First name: {}", self.first_name),
          format!("Last name: {}", self.last_name),
          format!("ID: {}", self.id),
      ].into_iter()
  }
}

fn main() {
  let employee = Employee {
      first_name: "Alice".to_owned(),
      last_name: "Smith".to_owned(),
      id: "ab123".to_owned(),
  };
  println!("Employee Details:");
  for detail in employee {
      println!("{detail}");
  }
}

Iterator methods

// In this exercise, you'll learn some of the unique advantages that iterators
// can offer. Follow the steps to complete the exercise.

// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String {
    let mut c = input.chars();
    match c.next() {
        None => String::new(),
        Some(first) => ???,
    }
}

// Step 2.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
    vec![]
}

// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String {
    String::new()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_success() {
        assert_eq!(capitalize_first("hello"), "Hello");
    }

    #[test]
    fn test_empty() {
        assert_eq!(capitalize_first(""), "");
    }

    #[test]
    fn test_iterate_string_vec() {
        let words = vec!["hello", "world"];
        assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
    }

    #[test]
    fn test_iterate_into_string() {
        let words = vec!["hello", " ", "world"];
        assert_eq!(capitalize_words_string(&words), "Hello World");
    }
}
Solution
#![allow(unused)]
fn main() {
pub fn capitalize_first(input: &str) -> String {
  let mut c = input.chars();
  match c.next() {
      None => String::new(),
      Some(first) => format!("{}{}", first.to_uppercase(), c.as_str()),
  }
}

pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
  words.iter().map(|w| capitalize_first(w)).collect()
}

pub fn capitalize_words_string(words: &[&str]) -> String {
  words.iter().map(|w| capitalize_first(w)).collect::<Vec<String>>().join("")
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_success() {
      assert_eq!(capitalize_first("hello"), "Hello");
  }

  #[test]
  fn test_empty() {
      assert_eq!(capitalize_first(""), "");
  }

  #[test]
  fn test_iterate_string_vec() {
      let words = vec!["hello", "world"];
      assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
  }

  #[test]
  fn test_iterate_into_string() {
      let words = vec!["hello", " ", "world"];
      assert_eq!(capitalize_words_string(&words), "Hello World");
  }
}
}