After the question has been edited, it seems that the number of rows and columns could be arbitrary.
The previous attempt (kept under the below line) considered only a fixed number of rows.
The example provided in the question makes extensive use of vectors, but we can generalise to any kind of iterator.
The main advantage is that we do not need to allocate the transposed result as a whole; we can just consume the partial results on the fly if the whole storage is not necessary.
The idea here is to build our own TransposeIterator structure, keeping the provided row-iterators, in order to consume all of them at each invocation of .next().
The use of IntoIterator instead of Iterator is just a convenience, so that we can directly pass structured data instead of explicitly making iterators at the call site.
mod transpose {
pub struct TransposeIterator<I: IntoIterator> {
iters: Vec<I::IntoIter>,
}
impl<I: IntoIterator> TransposeIterator<I> {
pub fn new(iters: impl IntoIterator<Item = I>) -> Self {
let iters = iters.into_iter().map(|i| i.into_iter());
Self {
iters: Vec::from_iter(iters),
}
}
}
impl<I: IntoIterator> Iterator for TransposeIterator<I> {
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
let mut result = Vec::with_capacity(self.iters.len());
for it in self.iters.iter_mut() {
if let Some(elem) = it.next() {
result.push(elem);
} else {
return None;
}
}
Some(result)
}
}
}
fn main() {
use transpose::TransposeIterator;
let mut data =
vec![[11, 12, 13], [21, 22, 23], [31, 32, 33], [41, 42, 43]];
for row in data.iter() {
println!("{:?}", row);
}
println!("~~~~ consumes original data ~~~~");
for row in TransposeIterator::new(data.clone()) {
println!("{:?}", row);
}
println!("~~~~ references original data ~~~~");
for row in TransposeIterator::new(&data) {
println!("{:?}", row);
}
println!("~~~~ mutably references original data ~~~~");
for mut row in TransposeIterator::new(&mut data) {
for elem in row.iter_mut() {
**elem += 900;
}
println!("{:?}", row);
}
}
/*
[11, 12, 13]
[21, 22, 23]
[31, 32, 33]
[41, 42, 43]
~~~~ consumes original data ~~~~
[11, 21, 31, 41]
[12, 22, 32, 42]
[13, 23, 33, 43]
~~~~ references original data ~~~~
[11, 21, 31, 41]
[12, 22, 32, 42]
[13, 23, 33, 43]
~~~~ mutably references original data ~~~~
[911, 921, 931, 941]
[912, 922, 932, 942]
[913, 923, 933, 943]
*/
Initial answer
I would do it with two nested invocations of std::iter::zip().
The best solution is certainly itertools::multizip() (it yields tuples, not arrays, I guess this is not important).
fn some_func<I: IntoIterator>(
i0: I,
i1: I,
i2: I,
) -> impl Iterator<Item = [I::Item; 3]> {
std::iter::zip(i0, std::iter::zip(i1, i2))
.map(|(e1, (e2, e3))| [e1, e2, e3])
}
fn main() {
for k in std::iter::zip([1, 2, 3], std::iter::zip([4, 5, 6], [7, 8, 9])) {
println!("{k:?}")
}
println!("~~~~ consumes original data ~~~~~~~~~~~~");
for k in some_func([1, 2, 3], [4, 5, 6], [7, 8, 9]) {
println!("{k:?}")
}
println!("~~~~ references original data ~~~~~~~~~~~~");
for k in some_func(&[1, 2], &[4, 5], &[7, 8]) {
println!("{k:?}")
}
println!("~~~~ consumes original data ~~~~~~~~~~~~");
for k in itertools::multizip(([1, 2, 3], [4, 5, 6], [7, 8, 9])) {
println!("{k:?}")
}
println!("~~~~ references original data ~~~~~~~~~~~~");
for k in itertools::multizip((&[1, 2], &[4, 5], &[7, 8])) {
println!("{k:?}")
}
}
/*
(1, (4, 7))
(2, (5, 8))
(3, (6, 9))
~~~~ consumes original data ~~~~~~~~~~~~
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]
~~~~ references original data ~~~~~~~~~~~~
[1, 4, 7]
[2, 5, 8]
~~~~ consumes original data ~~~~~~~~~~~~
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)
~~~~ references original data ~~~~~~~~~~~~
(1, 4, 7)
(2, 5, 8)
*/