10

Supposing I have a vector of structs like so:


struct Test {
    id:u32,
    amount:u32
 }
 
 fn main() {
    let test_vec:Vec<Test> = vec![Test{id:1,amount:3}, Test{id:3,amount:4}];
 }

Is there a way to get this into a polars dataframe with the column names being the struct fields?

Hoping to get an output as follows:

   id  amount
0   1       3
1   3       4
3
  • 1
    A dataframe is organized by column, not by row. It looks to me like you'll have to create the dataframe from series manually. Commented Jul 29, 2022 at 17:05
  • Thanks for the advice, gave it a go but found it to verbose and settled on the below solution! Commented Aug 2, 2022 at 15:36
  • For the opposite question, see Convert Polars dataframe to vector of structs. Commented Jul 6, 2024 at 21:26

2 Answers 2

15

I dislike the accepted answer for a couple of reasons

  1. It is type unsafe, and in fact you loose type information if you convert for example a chrono::NaiveDate field - it will come back as a str in your DataFrame.
  2. It is inefficient, since you need to serialize and deserialize your data.

I think a much better solution is a macro:

macro_rules! struct_to_dataframe {
    ($input:expr, [$($field:ident),+]) => {
        {
            let len = $input.len().to_owned();

            // Extract the field values into separate vectors
            $(let mut $field = Vec::with_capacity(len);)*

            for e in $input.into_iter() {
                $($field.push(e.$field);)*
            }
            df! {
                $(stringify!($field) => $field,)*
            }
        }
    };
}

You should be able to call it like so:

struct Test {
    id:u32,
    amount:u32
}

impl Test {
    fn new(id:u32, amount:u32) -> Self{
        Test{id,amount}
    }
}
let test_vec:Vec<Test> = vec![Test::new(1,3), Test::new(3,4)];
let df = struct_to_dataframe!(test_vec, [id, amount]).unwrap();
Sign up to request clarification or add additional context in comments.

1 Comment

This is great, thank you! I have tweaked the macro to use with_capacity(), for much more efficient creation of struct vectors with many elements.
6

After a lot of head banging, I found the following solution.

If you have a vector of a custom struct, to get it into a Polars dataframe you can do the following:

// 1. Derive serde::Serialize for your struct

#[derive(Serialize)]
struct Test {
    id:u32,
    amount:u32
}

// (Adding new method here for quality of life).

impl Test {
    fn new(id:u32, amount:u32) -> Self{
        Test{id,amount}
    }
}


// 2. Jsonify your struct Vec
let test_vec:Vec<Test> = vec![Test::new(1,3), Test::new(3,4)];
let json = serde_json::to_string(&test_vec).unwrap();

// 3. Create cursor from json 
let cursor = Cursor::new(json);

// 4. Create polars DataFrame from reading cursor as json
let df = JsonReader::new(cursor)
            .finish()
            .unwrap();
    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.