Array of structs to multiple arrays of primitives without size parameter

I want to pull out a series of values from an array of structs, into bare arrays so that I can process them elsewhere, but without needing the size of the array (I want it to follow the initial array's number), and preferably without going through a vector either. It's little enough data that copies are fine. I can do this in a couple of calls, but I wondered if there's a more idiomatic way to do this.

This is what I have now:

struct TwoFields {
  first_val: f64,
  second_val: f64
}

const NUM_ELEMENTS: usize = 4;

// Inside a function
let array_of_structs: [TwoFields ; NUM_ELEMENTS] = // They're initialized
let array_of_first: [f64; NUM_ELEMENTS] = array_of_structs
  .iter()
  .map(|cur| cur.first_val)
  .collect::<Vec<f64>>()
  .try_into()
  .unwrap();
let array_of_second: [f64; NUM_ELEMENTS] = array_of_structs
  .iter()
  .map(|cur| cur.second_val)
  .collect::<Vec<f64>>()
  .try_into()
  .unwrap();

What I'd like to do is something similar to this (which does not work) :

let (array_of_first, array_of_second) = array_of_structs
  .iter()
  .map(|cur| (cur.first_val, cur.second_val))
  .collect(); // turbofish I'm OK with, but again, that's not enough

In particular though, in the first method you have to use the same size constant. That's fine, except I'd rather the "produced" array(s) follow the size of the input array, because while the compiler will scream if they're different, I'd rather it "just work" for me, rather than have to input it twice.

Any thoughts on this, or whatever is the best way to do this? As I said, copies are fine here.

You could use array::map, at least if your struct is Copy.

#[derive(Default, Copy, Clone)]
struct TwoFields {
  first_val: f64,
  second_val: f64
}

const NUM_ELEMENTS: usize = 4;

fn main() {
    // Inside a function
    let array_of_structs: [TwoFields ; NUM_ELEMENTS] = Default::default();
    let array_of_first: [f64; NUM_ELEMENTS] = array_of_structs.map(|cur| cur.first_val);
    let array_of_second: [f64; NUM_ELEMENTS] = array_of_structs.map(|cur| cur.second_val);
}
1 Like

I'll definitely do that versus the loop through try_into like I was doing before. That alone is useful. The previous method was in a post I found online. Nowhere did it mention map directly on the array.

Any way to do this in one line that produces two arrays? If not, this was still great, and you'll get the "answer" for it.

Depending on how old the post was, it might have simply not existed at the time. The API is only on stable Rust since September 2021.

No good way off the top of my head.

1 Like

There is Iterator::unzip() although that doesn't work with constant-sized arrays, so you'd try_into() twice at the end.