Parse complex vector into vectors of tuples

I have a vector of data stored as:
[1,2,3,4,a,b,c,d,5,6,7,8,e,f,g,h....]
I need to return a vector of vector of tuples Vec<Vec<(,)>>
where each individual vector looks like:
[(1,a), (5,e)...]
[ (2,b), (6,f)...]
[(3,c), (7,g)...]
(4,d),(8,h)...]

I need a reasonably efficient means of doing so. I have a solution but I'm doing more copies than necessary (I'm still wrapping my head around some of these concepts). What can I do to tighten this up?

pub fn element_data(&self) -> Vec<Vec<(f32,f32)>> {
        let mut results: Vec<Vec<(f32,f32)>> = Vec::new();
        // extract each elements data
        let num_elements = 4;

        for element in 0..=num_elements {
            // iterate over the data and extract the current elements data, skipping over other
            //elements [0,3,7,...],
            let datavec: Vec<f32> = self.data
                .iter()
                .skip((element) as usize)
                .step_by(num_elements as usize)
                .copied()
                .map(|x| /* modify data here */ x)
                .collect_vec();

            let datapairs: Vec<(f32,f32)> = datavec
                .into_iter()
                .tuples::<(_,_)>()
                .collect::<Vec<_>>();

            results.push(datapairs); // save the resulting vector
        }
        results // return vector of vectors
    }

I'm not at a keyboard right now, but I'd look into the chunks iterator method. Specifically, if you do iter.chunks(4).chunks(2), it'll group each group of four, and then group each pair of groups. I can give an example later if you want.

2 Likes

Assuming this is a Vec or slice, you can use https://doc.rust-lang.org/std/primitive.slice.html#method.as_chunks something like https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=387813bf1f2b202aed7dc660b20cd33f.

(Note that the .0s there are ignoring any remainder elements; you'll need to decide how you want to handle that.)

1 Like

Right, I forgot there's no native std chunks method on iterators (yet). You can take a look at itertools if you need that, but otherwise, here's a full solution using slice::as_chunks. To change the chunk size, just change the 4 in the first call to as_chunks. Note that, since it's a const generic, that number can't be determined at runtime. If that's a requirement, use the chunk method from the itertools crate instead (it seems you're already aware of it, given that you use methods from it in your own solution).

1 Like

i think it would help to know what the modification you want to apply to the data is

A u32 to f32 conversion.

something like this maybe?

let mut result=vec![Vec::default();num_elements];
    for chunk in self.data.chunks_exact(num_elements*2){
        for i in 0..num_elements{
            result[i].push((chunk[i] as f32, chunk[i+num_elements] as f32));
        }
    }

The actual floating point conversion is:

.map(|x| I17F15::from_bits(x as i32).to_num::<f32>());

I'm converting a signed/fixed point to a float using the fixed crate. I left it out to keep the example simple.