 # Create an iterator like zip that takes iterators of specific items

I have some vectors consisting on TimeValue tuples ie type TimeValue = (DateTime, f64);
Now I want to add these types of vectors together. However, the datetime values have to match between vectors . For example data like below. Missing data has to be ignored.

``````        let d1 = Utc.ymd(2019, 12, 9).and_hms(1, 1, 0);
let d2 = Utc.ymd(2019, 12, 9).and_hms(1, 2, 0);
let d3 = Utc.ymd(2019, 12, 9).and_hms(1, 3, 0);
let d4 = Utc.ymd(2019, 12, 9).and_hms(1, 4, 0);
let d5 = Utc.ymd(2019, 12, 9).and_hms(1, 5, 0);
let d6 = Utc.ymd(2019, 12, 9).and_hms(1, 6, 0);
let d7 = Utc.ymd(2019, 12, 9).and_hms(1, 7, 0);

let lhs_values = vec![(d1, 1.0), (d3, 3.0), (d4, 4.0), (d5, 5.0), (d6, 6.0)];
let rhs_values = vec![(d1, 1.0), (d2, 2.0), (d3, 3.0), (d5, 5.0), (d6, 6.0), (d7, 7.0)];
``````

The following code seems to work. (truncate is a custom method. Just assume datetimes are truncated to the minute say)

``````        let mut it_lhs = lhs_values.iter();
let mut it_rhs = rhs_values.iter();

let mut it_lhs_value = it_lhs.next();
let mut it_rhs_value = it_rhs.next();

loop {
match (it_lhs_value, it_rhs_value) {
(Some(lhs_row), Some(rhs_row)) => {

let lhs_dt: DateTime<Utc> = lhs_row.0.truncate(chrono::Duration::minutes(1));
let rhs_dt: DateTime<Utc> = rhs_row.0.truncate(chrono::Duration::minutes(1));

if lhs_dt > rhs_dt {
it_rhs_value = it_rhs.next();
continue;
}
else if rhs_dt > lhs_dt {
it_lhs_value = it_lhs.next();
continue;
}
else {

// Do what I need here as the datetimes match for the pair

it_rhs_value = it_rhs.next();
it_lhs_value = it_lhs.next();
}
},
(Some(lhs_row), None) => {
it_lhs_value = it_lhs.next();
continue
},
(None, Some(rhs_row)) => {
it_rhs_value = it_rhs.next();
continue
},
(None, None) => break,
}
}
``````

This is not that elegant though. I thought I may be able to create my own iterator that does this for me like zip. The zip code https://doc.rust-lang.org/src/core/iter/adapters/zip.rs.html#12 is quite complicated though . How can I define an iterator that takes two iterators of TimeValue values ?

So far I have

``````pub struct TimeValueZip<A> {
a: A,
b: A
}

impl<A: Iterator,> TimeValueZip<A> {
pub fn new(a: A, b: A) -> TimeValueZip<A> {
TimeValueZip{
a: a,
b: b
}
}
}

impl<A> Iterator for TimeValueZip<A> where A: Iterator
{
type Item = (A::Item, A::Item);

// Here, we define the sequence using `.curr` and `.next`.
// The return type is `Option<T>`:
//     * When the `Iterator` is finished, `None` is returned.
//     * Otherwise, the next value is wrapped in `Some` and returned.
fn next(&mut self) -> Option<Self::Item> {

}
}
``````

How do I specify that the iterators have to be iterators to TimeValues ?

Thanks

You can specify associated types in the trait bound, `A: Iterator<Item = TimeValue>`

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.