Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A tuple windows iterator that returns options #319

Open
paulkernfeld opened this issue Dec 1, 2018 · 0 comments
Open

A tuple windows iterator that returns options #319

paulkernfeld opened this issue Dec 1, 2018 · 0 comments

Comments

@paulkernfeld
Copy link

paulkernfeld commented Dec 1, 2018

I'm not really sure of the right words to describe what I'm looking for, so possibly this already exists.

I'd like something that is like zipping an iterator with one or more staggered copies of itself. For example, for a window size of 3, on an iterator over [1, 2, 3, 4, 5], this would yield:

(None,                1)
(Some((None   , 1 )), 2)
(Some((Some(1), 2 )), 3)
(Some((Some(2), 3 )), 4)
(Some((Some(3), 4 )), 5)

I wanted this for a machine learning application where I'm trying to predict the next element of a sequence given the previous N elements. Perhaps this is also useful for other purposes, but I'm not sure that it is.

I have implemented a proof-of-concept. Although the code could be improved in many ways, I think it's correct. If this would be an interesting addition to itertools, I'd be happy to refine these implementations to fix some of the issues.

/// Given an iterator [1, 2, 3, 4], this will yield:
/// (None,    1)
/// (Some(1), 2)
/// (Some(2), 3)
/// (Some(3), 4)
pub fn tuple2_windows_prefix<T: Clone, I: Iterator<Item = T>>(
    iterator: I,
) -> impl Iterator<Item = (Option<T>, T)> {
    iterator.scan(None, |previous_item, this_item| {
        let to_return = (previous_item.clone(), this_item.clone());
        *previous_item = Some(this_item.clone());
        Some(to_return)
    })
}

#[test]
fn test_tuple2_windows_prefix() {
    assert_eq!(
        vec![(None, 1), (Some(1), 2), (Some(2), 3)],
        tuple2_windows_prefix(vec![1, 2, 3].into_iter()).collect_vec()
    )
}

/// Given an iterator [1, 2, 3, 4, 5], this will yield:
/// (None,                1)
/// (Some((None   , 1 )), 2)
/// (Some((Some(1), 2 )), 3)
/// (Some((Some(2), 3 )), 4)
/// (Some((Some(3), 4 )), 5)
pub fn tuple3_windows_prefix<T: Clone, I: Iterator<Item = T>>(
    iterator: I,
) -> impl Iterator<Item = (Option<(Option<T>, T)>, T)> {
    iterator.scan(None, |previous_items, this_item| {
        let previous_items: &mut Option<(Option<T>, T)> = previous_items;
        let (previous_items_new, to_return) = match previous_items {
            None => (Some((None, this_item.clone())), (None, this_item)),
            Some((None, previous_item)) => (
                Some((Some(previous_item.clone()), this_item.clone())),
                (Some((None, previous_item.clone())), this_item),
            ),
            Some((Some(previous2_item), previous_item)) => (
                Some((Some(previous_item.clone()), this_item.clone())),
                (
                    Some((Some(previous2_item.clone()), previous_item.clone())),
                    this_item,
                ),
            ),
        };
        *previous_items = previous_items_new;
        Some(to_return)
    })
}

#[test]
fn test_tuple3_windows_prefix() {
    assert_eq!(
        vec![
            (None, 1),
            (Some((None, 1)), 2),
            (Some((Some(1), 2)), 3),
            (Some((Some(2), 3)), 4)
        ],
        tuple3_windows_prefix(vec![1, 2, 3, 4].into_iter()).collect_vec()
    )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant