Path: blob/main/crates/polars-ops/src/chunked_array/array/join.rs
6939 views
use std::fmt::Write;12use super::*;34fn join_literal(5ca: &ArrayChunked,6separator: &str,7ignore_nulls: bool,8) -> PolarsResult<StringChunked> {9let DataType::Array(_, _) = ca.dtype() else {10unreachable!()11};1213let mut buf = String::with_capacity(128);14let mut builder = StringChunkedBuilder::new(ca.name().clone(), ca.len());1516ca.for_each_amortized(|opt_s| {17let opt_val = opt_s.and_then(|s| {18// make sure that we don't write values of previous iteration19buf.clear();20let ca = s.as_ref().str().unwrap();2122if ca.null_count() != 0 && !ignore_nulls {23return None;24}25for arr in ca.downcast_iter() {26for val in arr.non_null_values_iter() {27buf.write_str(val).unwrap();28buf.write_str(separator).unwrap();29}30}3132// last value should not have a separator, so slice that off33// saturating sub because there might have been nothing written.34Some(&buf[..buf.len().saturating_sub(separator.len())])35});36builder.append_option(opt_val)37});38Ok(builder.finish())39}4041fn join_many(42ca: &ArrayChunked,43separator: &StringChunked,44ignore_nulls: bool,45) -> PolarsResult<StringChunked> {46polars_ensure!(47ca.len() == separator.len(),48length_mismatch = "arr.join",49ca.len(),50separator.len()51);5253let mut buf = String::new();54let mut builder = StringChunkedBuilder::new(ca.name().clone(), ca.len());5556{ ca.amortized_iter() }57.zip(separator)58.for_each(|(opt_s, opt_sep)| match opt_sep {59Some(separator) => {60let opt_val = opt_s.and_then(|s| {61// make sure that we don't write values of previous iteration62buf.clear();63let ca = s.as_ref().str().unwrap();6465if ca.null_count() != 0 && !ignore_nulls {66return None;67}6869for arr in ca.downcast_iter() {70for val in arr.non_null_values_iter() {71buf.write_str(val).unwrap();72buf.write_str(separator).unwrap();73}74}75// last value should not have a separator, so slice that off76// saturating sub because there might have been nothing written.77Some(&buf[..buf.len().saturating_sub(separator.len())])78});79builder.append_option(opt_val)80},81_ => builder.append_null(),82});83Ok(builder.finish())84}8586/// In case the inner dtype [`DataType::String`], the individual items will be joined into a87/// single string separated by `separator`.88pub fn array_join(89ca: &ArrayChunked,90separator: &StringChunked,91ignore_nulls: bool,92) -> PolarsResult<StringChunked> {93match ca.inner_dtype() {94DataType::String => match separator.len() {951 => match separator.get(0) {96Some(separator) => join_literal(ca, separator, ignore_nulls),97_ => Ok(StringChunked::full_null(ca.name().clone(), ca.len())),98},99_ => join_many(ca, separator, ignore_nulls),100},101dt => polars_bail!(op = "`array.join`", got = dt, expected = "String"),102}103}104105106