假设我有一个像这样的结构向量:
struct Test {
id:u32,
amount:u32
}
fn main() {
let test_vec:Vec<Test> = vec![Test{id:1,amount:3}, Test{id:3,amount:4}];
}
有没有办法将其放入极坐标数据框中,其中列名称为结构字段?
希望得到如下输出:
id amount
0 1 3
1 3 4
经过一番苦思冥想,我找到了以下解决方案。
如果您有自定义结构的向量,要将其放入 Polars 数据框中,您可以执行以下操作:
// 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();
出于几个原因,我不喜欢接受的答案
chrono::NaiveDate
字段,您就会丢失类型信息 - 它将作为 str
返回到您的 DataFrame
中。我认为更好的解决方案是宏:
macro_rules! struct_to_dataframe {
($input:expr, [$($field:ident),+]) => {
{
// Extract the field values into separate vectors
$(let mut $field = Vec::new();)*
for e in $input.into_iter() {
$($field.push(e.$field);)*
}
df! {
$(stringify!($field) => $field,)*
}
}
};
}
你应该可以这样称呼它:
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();
让测试给出:
struct Test {
id: u32,
amount: u32,
field3: String,
field4: Option<f64>,
}
impl Test {
fn new(id:u32, amount:u32, field3: String, field4: Option<f64>) -> Self {
Test { id, amount, field3, field4 }
}
}
let test_vec:Vec<Test> = vec![
Test::new(1, 3, "foo".to_string, Some(6.43)),
Test::new(3, 4, "bar".to_string, Some(8.0)),
];
是否可以通过结构名称显式更改字段
[id, amount, field3, field4]
?
即通过Test改变
[id, amount, field3, field4]
。
let df = struct_to_dataframe!(test_vec, Test).unwrap();
这些改变之后
struct_to_dataframe
会是什么样子?