use polars_core::prelude::*;
use crate::prelude::*;
fn resolve_component<T>(
component: &ChunkedArray<T>,
existing: impl FnOnce() -> ChunkedArray<T>,
n: usize,
) -> PolarsResult<ChunkedArray<T>>
where
T: PolarsNumericType,
ChunkedArray<T>: ChunkZip<T>,
{
if component.len() == 1 {
if let Some(value) = component.get(0) {
Ok(ChunkedArray::<T>::full(PlSmallStr::EMPTY, value, n))
} else {
Ok(existing())
}
} else {
component.zip_with(&component.is_not_null(), &existing())
}
}
#[cfg(feature = "dtype-datetime")]
#[allow(clippy::too_many_arguments)]
pub fn replace_datetime(
ca: &DatetimeChunked,
year: &Int32Chunked,
month: &Int8Chunked,
day: &Int8Chunked,
hour: &Int8Chunked,
minute: &Int8Chunked,
second: &Int8Chunked,
nanosecond: &Int32Chunked,
ambiguous: &StringChunked,
) -> PolarsResult<DatetimeChunked> {
let n = [
ca.len(),
year.len(),
month.len(),
day.len(),
hour.len(),
minute.len(),
second.len(),
nanosecond.len(),
ambiguous.len(),
]
.into_iter()
.find(|l| *l != 1)
.unwrap_or(1);
for (i, (name, length)) in [
("self", ca.len()),
("year", year.len()),
("month", month.len()),
("day", day.len()),
("hour", hour.len()),
("minute", minute.len()),
("second", second.len()),
("nanosecond", nanosecond.len()),
("ambiguous", ambiguous.len()),
]
.into_iter()
.enumerate()
{
polars_ensure!(
length == n || length == 1,
length_mismatch = "dt.replace",
length,
n,
argument = name,
argument_idx = i
);
}
let year = &resolve_component(year, || ca.year(), n)?;
let month = &resolve_component(month, || ca.month(), n)?;
let day = &resolve_component(day, || ca.day(), n)?;
let hour = &resolve_component(hour, || ca.hour(), n)?;
let minute = &resolve_component(minute, || ca.minute(), n)?;
let second = &resolve_component(second, || ca.second(), n)?;
let nanosecond = &resolve_component(nanosecond, || ca.nanosecond(), n)?;
let mut out = DatetimeChunked::new_from_parts(
year,
month,
day,
hour,
minute,
second,
nanosecond,
ambiguous,
&ca.time_unit(),
ca.time_zone().clone(),
ca.name().clone(),
)?;
if ca.has_nulls() {
out.physical_mut()
.set_validity(ca.physical().rechunk_validity());
}
Ok(out)
}
#[cfg(feature = "dtype-date")]
pub fn replace_date(
ca: &DateChunked,
year: &Int32Chunked,
month: &Int8Chunked,
day: &Int8Chunked,
) -> PolarsResult<DateChunked> {
let n = ca.len();
let year = &resolve_component(year, || ca.year(), n)?;
let month = &resolve_component(month, || ca.month(), n)?;
let day = &resolve_component(day, || ca.day(), n)?;
let mut out = DateChunked::new_from_parts(year, month, day, ca.name().clone())?;
if ca.has_nulls() {
out.physical_mut()
.set_validity(ca.physical().rechunk_validity());
}
Ok(out)
}