Iterator + Map - How do divide every element, including the last element, by the last element

I am writing a function to convert string dates in a vector to pixel locations on a canvas. I initially achieved this via a series of for loops. But I would really like to be able to do this via an iterator with a series of filter_maps and maps as required. I think I have most of it figured out but in the first map (duration) I cannot figure out how to divide every element in the iterator, including the last element, by the last element. Any assistance will be appreciated.

pub fn line_graph_x_data() -> Result<Vec<f64>, CustomError> {

    let date_vec = [
        "2026-02-02".to_string(),
        "2026-03-14".to_string(),
        "2026-03-29".to_string(),
        "2026-04-09".to_string(),
        "2026-05-22".to_string(),
        "2026-07-15".to_string(),
    ];

    // 1) convert strings to naive dates
    // 2) Determine number of days between each date and first date ("2026-02-02") in the date_vec
    // 3) Determine number of days between top and bottom dates (earliest to most recent)
    // 4) Apply formula (((each_value - min_vallue)/(max_value - min_value)) * 600) + 100) and round

// working code below #################

    // let mut navidate_vec: Vec<NaiveDate> = Vec::new();

    // for i in 0..date_vec.len() {
    //     let nav_date = NaiveDate::parse_from_str(&date_vec[i], "%Y-%m-%d")?;
    //     navidate_vec.push(nav_date);
    // }

    // let mut numerator_vec = Vec::new();

    // for i in 0..navidate_vec.len() {
    //     let day_delta = navidate_vec[i].signed_duration_since(navidate_vec[0]).num_days();
    //     numerator_vec.push(day_delta);
    // }

    // let denominator = numerator_vec[numerator_vec.len()-1];

    // let mut x_axis_pixels = Vec::new();

    // for i in 0..numerator_vec.len() {
    //     let num_pixels = (((numerator_vec[i] as f64 / denominator as f64)) * 600.0) + 100.0;
    //     x_axis_pixels.push(num_pixels.round());
    // }

    // Ok(x_axis_pixels)

// working code above #################

    let x_axis = date_vec.iter()
        .filter_map(|item| {
            let nav_date = NaiveDate::parse_from_str(&item, "%Y-%m-%d").ok();
            return nav_date
        })
        .filter_map(|nav_date| {
            let starting_date = NaiveDate::parse_from_str(&date_vec[0], "%Y-%m-%d").ok().expect("error");
            let num_days = nav_date.signed_duration_since(starting_date)
            .num_days();
            return Some(num_days)
        })
        .map(|duration| {
            let ratio = duration as f64 / last duration item as f64 ???????
            return ratio
        })
        .map(|ratio| {
            let x_values = ((ratio * 600.0) + 100.0).round();
            return x_values
        })
        .collect::<Vec<f64>>();

}

Iterators are great for replacing for loops, but they don't mimic indexing. Fortunately you want the last item, and you're working with a DoubleEndedIterator, so you can get the last element. This won't work if it's not a DoubleEndedIterator or if your map functions have state that is sensitive to order.

I also got rid of a bunch of clippy warnings.

// moved this out so it doesn't have to be computed every time
let starting_date = NaiveDate::parse_from_str(&date_vec[0], "%Y-%m-%d").expect("error");
let mut duration_iter = date_vec
    .iter()
    .filter_map(|item| NaiveDate::parse_from_str(item, "%Y-%m-%d").ok())
    .map(|nav_date| nav_date.signed_duration_since(starting_date).num_days());

// this is a DoubleEndedIterator so you can get the last item directly
let last_duration = duration_iter.next_back().unwrap();

let x_axis = duration_iter
    .chain([last_duration]) // add the last one back in
    .map(|duration| duration as f64 / last_duration as f64)
    // .chain([1.0]) or you could just put a 1 here since anything / anything = 1
    .map(|ratio| ((ratio * 600.0) + 100.0).round())
    .collect::<Vec<f64>>();

Thank you. Did not know you could crate a collection with an iterator and not have a ".collect" every time. Two questions. 1) In .chain([last_duration]), the square brackets are to convert a single value into an array which implements the iterator trait while i64 does not? 2) I did not understand the commented out line starting with .chain([1.0]).

The IntoIterator trait, but otherwise yes. iter::once(value) is an alternative.

They meant: instead of adding the last value back to the end and dividing by the last value later, you could just add 1.0 to the end after the division happens for everything before the last element.

 let x_axis = duration_iter
-    .chain([last_duration]) // add the last one back in
     .map(|duration| duration as f64 / last_duration as f64)
+    .chain([1.0]) // `add last_duration / last_duration` (`== 1.0`) to the end
     .map(|ratio| ((ratio * 600.0) + 100.0).round())
     .collect::<Vec<f64>>();

Or you could add 700.0 after the map, using the same sort of reasoning.

 let x_axis = duration_iter
     .map(|duration| duration as f64 / last_duration as f64)
-    .chain([1.0]) // `add last_duration / last_duration` (`== 1.0`) to the end
     .map(|ratio| ((ratio * 600.0) + 100.0).round())
+    .chain([700.0])
     .collect::<Vec<f64>>();

To avoid having to artificially put an elemnt back into the iterator, you can use rev and peek to look at the last element without consuming it.

let last_duration = *duration_iter.by_ref().rev().peekable().peek().unwrap();

let x_axis = duration_iter
    .map(|duration| duration as f64 / last_duration as f64)
    .map(|ratio| ((ratio * 600.0) + 100.0).round())
    .collect::<Vec<f64>>();

This doesn't work unless you continue to use the Peekable you made. The element still gets removed from duration_iter.

let mut peekable_duration = duration_iter.rev().peekable();
let last_duration = *peekable_duration.peek().unwrap();

let x_axis = peekable_duration.rev()
    .map(|duration| duration as f64 / last_duration as f64)
    .map(|ratio| ((ratio * 600.0) + 100.0).round())
    .collect::<Vec<f64>>();

And now we're using rev twice and have another variable, so it's become more complicated than just chaining the element onto the end.

Oops, I don't know how I missed that. That my my solution a little unsatisfying.