polars_python/series/
scatter.rs1use arrow::array::Array;
2use polars::prelude::*;
3use pyo3::prelude::*;
4
5use super::PySeries;
6use crate::utils::EnterPolarsExt;
7
8#[pymethods]
9impl PySeries {
10 fn scatter(&mut self, py: Python<'_>, idx: PySeries, values: PySeries) -> PyResult<()> {
11 let s = std::mem::take(&mut self.series);
14 py.enter_polars(|| {
15 let result = scatter(s, &idx.series, &values.series);
16 match result {
17 Ok(out) => {
18 self.series = out;
19 Ok(())
20 },
21 Err((s, e)) => {
22 self.series = s;
24 Err(e)
25 },
26 }
27 })
28 }
29}
30
31fn scatter(mut s: Series, idx: &Series, values: &Series) -> Result<Series, (Series, PolarsError)> {
32 let logical_dtype = s.dtype().clone();
33
34 let idx = match polars_ops::prelude::convert_to_unsigned_index(idx, s.len()) {
35 Ok(idx) => idx,
36 Err(err) => return Err((s, err)),
37 };
38 let idx = idx.rechunk();
39 let idx = idx.downcast_as_array();
40
41 if idx.null_count() > 0 {
42 return Err((
43 s,
44 PolarsError::ComputeError("index values should not be null".into()),
45 ));
46 }
47
48 let idx = idx.values().as_slice();
49
50 let mut values = match values.to_physical_repr().cast(&s.dtype().to_physical()) {
51 Ok(values) => values,
52 Err(err) => return Err((s, err)),
53 };
54
55 if values.len() == 1 && idx.len() > 1 {
57 values = values.new_from_index(0, idx.len());
58 }
59
60 s = s.to_physical_repr().into_owned();
63 let s_mut_ref = &mut s;
64 scatter_impl(s_mut_ref, logical_dtype, idx, &values).map_err(|err| (s, err))
65}
66
67fn scatter_impl(
68 s: &mut Series,
69 logical_dtype: DataType,
70 idx: &[IdxSize],
71 values: &Series,
72) -> PolarsResult<Series> {
73 let mutable_s = s._get_inner_mut();
74
75 let s = match logical_dtype.to_physical() {
76 DataType::Int8 => {
77 let ca: &mut ChunkedArray<Int8Type> = mutable_s.as_mut();
78 let values = values.i8()?;
79 ca.scatter(idx, values)
80 },
81 DataType::Int16 => {
82 let ca: &mut ChunkedArray<Int16Type> = mutable_s.as_mut();
83 let values = values.i16()?;
84 ca.scatter(idx, values)
85 },
86 DataType::Int32 => {
87 let ca: &mut ChunkedArray<Int32Type> = mutable_s.as_mut();
88 let values = values.i32()?;
89 ca.scatter(idx, values)
90 },
91 DataType::Int64 => {
92 let ca: &mut ChunkedArray<Int64Type> = mutable_s.as_mut();
93 let values = values.i64()?;
94 ca.scatter(idx, values)
95 },
96 DataType::UInt8 => {
97 let ca: &mut ChunkedArray<UInt8Type> = mutable_s.as_mut();
98 let values = values.u8()?;
99 ca.scatter(idx, values)
100 },
101 DataType::UInt16 => {
102 let ca: &mut ChunkedArray<UInt16Type> = mutable_s.as_mut();
103 let values = values.u16()?;
104 ca.scatter(idx, values)
105 },
106 DataType::UInt32 => {
107 let ca: &mut ChunkedArray<UInt32Type> = mutable_s.as_mut();
108 let values = values.u32()?;
109 ca.scatter(idx, values)
110 },
111 DataType::UInt64 => {
112 let ca: &mut ChunkedArray<UInt64Type> = mutable_s.as_mut();
113 let values = values.u64()?;
114 ca.scatter(idx, values)
115 },
116 DataType::Float32 => {
117 let ca: &mut ChunkedArray<Float32Type> = mutable_s.as_mut();
118 let values = values.f32()?;
119 ca.scatter(idx, values)
120 },
121 DataType::Float64 => {
122 let ca: &mut ChunkedArray<Float64Type> = mutable_s.as_mut();
123 let values = values.f64()?;
124 ca.scatter(idx, values)
125 },
126 DataType::Boolean => {
127 let ca = s.bool()?;
128 let values = values.bool()?;
129 ca.scatter(idx, values)
130 },
131 DataType::String => {
132 let ca = s.str()?;
133 let values = values.str()?;
134 ca.scatter(idx, values)
135 },
136 _ => {
137 return Err(PolarsError::ComputeError(
138 format!("not yet implemented for dtype: {logical_dtype}").into(),
139 ));
140 },
141 };
142
143 s.and_then(|s| s.cast(&logical_dtype))
144}