use numpy::{PyArray1, PyReadonlyArray1, PyUntypedArrayMethods};
use pyo3::prelude::*;
use pyo3::types::PyList;
#[allow(clippy::collapsible_if)]
pub fn extract_vec_f64(obj: &Bound<'_, PyAny>) -> PyResult<Vec<f64>> {
if let Ok(arr) = obj.extract::<PyReadonlyArray1<'_, f64>>() {
return Ok(arr.as_slice()?.to_vec());
}
if let Ok(list) = obj.extract::<Vec<f64>>() {
return Ok(list);
}
if let Ok(values) = obj.getattr("values") {
if let Ok(arr) = values.extract::<PyReadonlyArray1<'_, f64>>() {
return Ok(arr.as_slice()?.to_vec());
}
}
if let Ok(to_numpy) = obj.getattr("to_numpy") {
if let Ok(arr_obj) = to_numpy.call0() {
if let Ok(arr) = arr_obj.extract::<PyReadonlyArray1<'_, f64>>() {
return Ok(arr.as_slice()?.to_vec());
}
}
}
Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
"Expected numpy array, pandas Series, polars Series, or list of floats",
))
}
#[allow(clippy::collapsible_if)]
pub fn extract_vec_i32(obj: &Bound<'_, PyAny>) -> PyResult<Vec<i32>> {
if let Ok(arr) = obj.extract::<PyReadonlyArray1<'_, i32>>() {
return Ok(arr.as_slice()?.to_vec());
}
if let Ok(arr) = obj.extract::<PyReadonlyArray1<'_, i64>>() {
return Ok(arr.as_slice()?.iter().map(|&x| x as i32).collect());
}
if let Ok(list) = obj.extract::<Vec<i32>>() {
return Ok(list);
}
if let Ok(list) = obj.extract::<Vec<i64>>() {
return Ok(list.into_iter().map(|x| x as i32).collect());
}
if let Ok(values) = obj.getattr("values") {
if let Ok(arr) = values.extract::<PyReadonlyArray1<'_, i32>>() {
return Ok(arr.as_slice()?.to_vec());
}
if let Ok(arr) = values.extract::<PyReadonlyArray1<'_, i64>>() {
return Ok(arr.as_slice()?.iter().map(|&x| x as i32).collect());
}
}
if let Ok(to_numpy) = obj.getattr("to_numpy") {
if let Ok(arr_obj) = to_numpy.call0() {
if let Ok(arr) = arr_obj.extract::<PyReadonlyArray1<'_, i32>>() {
return Ok(arr.as_slice()?.to_vec());
}
if let Ok(arr) = arr_obj.extract::<PyReadonlyArray1<'_, i64>>() {
return Ok(arr.as_slice()?.iter().map(|&x| x as i32).collect());
}
}
}
Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
"Expected numpy array, pandas Series, polars Series, or list of integers",
))
}
pub fn extract_optional_vec_f64(obj: Option<&Bound<'_, PyAny>>) -> PyResult<Option<Vec<f64>>> {
match obj {
Some(o) => Ok(Some(extract_vec_f64(o)?)),
None => Ok(None),
}
}
pub fn extract_optional_vec_i32(obj: Option<&Bound<'_, PyAny>>) -> PyResult<Option<Vec<i32>>> {
match obj {
Some(o) => Ok(Some(extract_vec_i32(o)?)),
None => Ok(None),
}
}
#[allow(dead_code)]
pub fn array_f64_to_vec(arr: PyReadonlyArray1<'_, f64>) -> Vec<f64> {
arr.as_slice().unwrap().to_vec()
}
#[allow(dead_code)]
pub fn array_i32_to_vec(arr: PyReadonlyArray1<'_, i32>) -> Vec<i32> {
arr.as_slice().unwrap().to_vec()
}
#[allow(dead_code)]
pub fn array_i64_to_vec(arr: PyReadonlyArray1<'_, i64>) -> Vec<i64> {
arr.as_slice().unwrap().to_vec()
}
#[allow(dead_code)]
pub fn vec_to_array_f64<'py>(py: Python<'py>, vec: Vec<f64>) -> Bound<'py, PyArray1<f64>> {
PyArray1::from_vec(py, vec)
}
#[allow(dead_code)]
pub fn vec_to_array_i32<'py>(py: Python<'py>, vec: Vec<i32>) -> Bound<'py, PyArray1<i32>> {
PyArray1::from_vec(py, vec)
}
#[allow(dead_code, clippy::collapsible_if)]
pub fn extract_2d_vec_f64(obj: &Bound<'_, PyAny>) -> PyResult<Vec<Vec<f64>>> {
if let Ok(list) = obj.extract::<Bound<'_, PyList>>() {
let mut result = Vec::with_capacity(list.len());
for item in list.iter() {
result.push(extract_vec_f64(&item)?);
}
return Ok(result);
}
if let Ok(list) = obj.extract::<Vec<Vec<f64>>>() {
return Ok(list);
}
if let Ok(values) = obj.getattr("values") {
if let Ok(arr) = values.extract::<numpy::PyReadonlyArray2<'_, f64>>() {
let shape = arr.shape();
let slice = arr.as_slice()?;
let mut result = Vec::with_capacity(shape[0]);
for i in 0..shape[0] {
let row: Vec<f64> = slice[i * shape[1]..(i + 1) * shape[1]].to_vec();
result.push(row);
}
return Ok(result);
}
}
Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
"Expected 2D array, DataFrame, or list of lists",
))
}