From f1b00353f36e5de4efc7cd1b4892163ac439d8e1 Mon Sep 17 00:00:00 2001 From: Ritchie Vink Date: Thu, 19 Jan 2023 14:52:14 +0100 Subject: [PATCH] feat(rust, python): allow unordered struct creating from anyvalues --- polars/polars-core/src/series/any_value.rs | 41 +++++++++++++--------- py-polars/tests/unit/test_struct.py | 9 ++--- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/polars/polars-core/src/series/any_value.rs b/polars/polars-core/src/series/any_value.rs index cf1a48eb99ed..0dbd2ae84773 100644 --- a/polars/polars-core/src/series/any_value.rs +++ b/polars/polars-core/src/series/any_value.rs @@ -125,25 +125,11 @@ impl Series { for av in av.iter() { match av { AnyValue::StructOwned(payload) => { + // TODO: optimize let av_fields = &payload.1; let av_values = &payload.0; - // all fields are available in this single value - // we can use the index to get value - if dtype_fields.len() == av_fields.len() { - for (l, r) in dtype_fields.iter().zip(av_fields.iter()) { - if l.name() != r.name() { - return Err(PolarsError::ComputeError( - "struct orders must remain the same".into(), - )); - } - } - let av_val = - av_values.get(i).cloned().unwrap_or(AnyValue::Null); - field_avs.push(av_val) - } - // not all fields are available, we search the proper field - else { + let mut append_by_search = || { // search for the name let mut pushed = false; for (av_fld, av_val) in av_fields.iter().zip(av_values) { @@ -156,6 +142,29 @@ impl Series { if !pushed { field_avs.push(AnyValue::Null) } + }; + + // all fields are available in this single value + // we can use the index to get value + if dtype_fields.len() == av_fields.len() { + let mut search = false; + for (l, r) in dtype_fields.iter().zip(av_fields.iter()) { + if l.name() != r.name() { + search = true; + } + } + if search { + append_by_search() + } else { + let av_val = + av_values.get(i).cloned().unwrap_or(AnyValue::Null); + field_avs.push(av_val) + } + } + // not all fields are available, we search the proper field + else { + // search for the name + append_by_search() } } _ => field_avs.push(AnyValue::Null), diff --git a/py-polars/tests/unit/test_struct.py b/py-polars/tests/unit/test_struct.py index a37dcbc808d5..095d06a73cae 100644 --- a/py-polars/tests/unit/test_struct.py +++ b/py-polars/tests/unit/test_struct.py @@ -457,12 +457,9 @@ def test_struct_comparison() -> None: def test_struct_order() -> None: - with pytest.raises(pl.ComputeError, match="struct orders must remain the same"): - pl.DataFrame( - { - "col1": [{"a": 1, "b": 2}, {"b": 4, "a": 3}], - } - ) + assert pl.DataFrame({"col1": [{"a": 1, "b": 2}, {"b": 4, "a": 3}],}).to_dict( + False + ) == {"col1": [{"a": 1, "b": 2}, {"a": 3, "b": 4}]} # null values should not trigger this assert (