Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Polars Dataframe from Vec<Struct>

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
like image 564
Sam Avatar asked Apr 17 '26 15:04

Sam


2 Answers

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();
like image 91
SirVer Avatar answered Apr 20 '26 12:04

SirVer


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();
    
like image 23
Sam Avatar answered Apr 20 '26 12:04

Sam



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!