Flat mapping arrays

I've got an array of 3 elements, and I want to create an iterator that cycles the elements a number of times. I tried the following code (included to show my intention):

let arr = [1, 2, 3];
iter::repeat(arr).take(10).flatten()

This doesn't work because array does not implement Iterator. I can't make an iterator by borrowing in a flat_map because I create a temporary borrow that would have to live beyond the function. The following does work:

iter::repeat(&arr).take(10).flatten()

but this relies on the optimizer being able to propagate the constant nature of the length of &arr. Are there any better solutions?

You can use Iterator::cycle:

arr.iter().cycle().take(10)

Are you referring to the fact that <&[T; N] as IntoIterator>::into_iter just delegates to [T]::iter, so N is erased?

Yeah exactly, the array is reinterpreted as a slice. It might make no difference to the asm though, I haven't looked. arr.iter() does the same thing.

(Off the top of my head) That seems unlikely to be a major performance issue even if the optimizer can't see through it; however, you raise an interesting point. It might be nice to have array::Iter(Mut)<T, N> (or whatever) instead of just delegating to the slice versions. Doing so would certainly break backwards compatibility, though, similar to array::IntoIter.

Speaking of which, you could use array::IntoIter:

std::array::IntoIter::new(arr).cycle().take(10)

However, since Cycle has to copy the whole struct, that might be worse if the optimizer is better at propagating constants than eliminating copies. Probably test it.

1 Like

IntoIterator for [T; N] is coming in 1.53, but until then std::array::IntoIter does the same thing.

2 Likes