use crate::array::Array;
use crate::error::{NumRs2Error, Result};
pub fn r_concatenate<T: Clone>(arrays: &[&Array<T>]) -> Result<Array<T>> {
if arrays.is_empty() {
return Err(NumRs2Error::InvalidOperation(
"Cannot concatenate empty array list".to_string(),
));
}
crate::array_ops::concatenate(arrays, 0)
}
pub fn c_concatenate<T: Clone>(arrays: &[&Array<T>]) -> Result<Array<T>> {
if arrays.is_empty() {
return Err(NumRs2Error::InvalidOperation(
"Cannot concatenate empty array list".to_string(),
));
}
let mut column_arrays = Vec::new();
for &arr in arrays {
if arr.ndim() == 1 {
let reshaped = arr.reshape(&[arr.len(), 1]);
column_arrays.push(reshaped);
} else {
column_arrays.push(arr.clone());
}
}
let column_refs: Vec<&Array<T>> = column_arrays.iter().collect();
crate::array_ops::concatenate(&column_refs, 1)
}
pub fn ix_<T: Clone>(sequences: &[&Array<T>]) -> Result<Vec<Array<T>>> {
if sequences.is_empty() {
return Ok(vec![]);
}
for (i, seq) in sequences.iter().enumerate() {
if seq.ndim() != 1 {
return Err(NumRs2Error::DimensionMismatch(format!(
"Input array {} must be 1-D, got {}-D",
i,
seq.ndim()
)));
}
}
let ndim = sequences.len();
let mut result = Vec::with_capacity(ndim);
for (axis_idx, &seq) in sequences.iter().enumerate() {
let mut shape = vec![1; ndim];
shape[axis_idx] = seq.len();
let reshaped = seq.reshape(&shape);
result.push(reshaped);
}
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_r_concatenate() {
let a = Array::from_vec(vec![1, 2, 3]);
let b = Array::from_vec(vec![4, 5, 6]);
let result = r_concatenate(&[&a, &b]).expect("operation should succeed");
assert_eq!(result.to_vec(), vec![1, 2, 3, 4, 5, 6]);
assert_eq!(result.shape(), vec![6]);
let a = Array::from_vec(vec![1, 2, 3, 4]).reshape(&[2, 2]);
let b = Array::from_vec(vec![5, 6, 7, 8]).reshape(&[2, 2]);
let result = r_concatenate(&[&a, &b]).expect("operation should succeed");
assert_eq!(result.shape(), vec![4, 2]);
assert_eq!(result.to_vec(), vec![1, 2, 3, 4, 5, 6, 7, 8]);
let result = r_concatenate::<i32>(&[]);
assert!(result.is_err());
}
#[test]
fn test_c_concatenate() {
let a = Array::from_vec(vec![1, 2, 3]);
let b = Array::from_vec(vec![4, 5, 6]);
let result = c_concatenate(&[&a, &b]).expect("operation should succeed");
assert_eq!(result.shape(), vec![3, 2]);
assert_eq!(result.to_vec(), vec![1, 2, 3, 4, 5, 6]);
let a = Array::from_vec(vec![1, 2, 3, 4]).reshape(&[2, 2]);
let b = Array::from_vec(vec![5, 6, 7, 8]).reshape(&[2, 2]);
let result = c_concatenate(&[&a, &b]).expect("operation should succeed");
assert_eq!(result.shape(), vec![2, 4]);
assert_eq!(result.to_vec(), vec![1, 3, 2, 4, 5, 7, 6, 8]);
let result = c_concatenate::<i32>(&[]);
assert!(result.is_err());
}
#[test]
fn test_ix_() {
let a = Array::from_vec(vec![0, 1, 2]);
let b = Array::from_vec(vec![3, 4]);
let indices = ix_(&[&a, &b]).expect("operation should succeed");
assert_eq!(indices.len(), 2);
assert_eq!(indices[0].shape(), vec![3, 1]);
assert_eq!(indices[1].shape(), vec![1, 2]);
assert_eq!(indices[0].to_vec(), vec![0, 1, 2]);
assert_eq!(indices[1].to_vec(), vec![3, 4]);
let x = Array::from_vec(vec![10, 11]);
let y = Array::from_vec(vec![20, 30]);
let z = Array::from_vec(vec![100]);
let indices_3d = ix_(&[&x, &y, &z]).expect("operation should succeed");
assert_eq!(indices_3d.len(), 3);
assert_eq!(indices_3d[0].shape(), vec![2, 1, 1]);
assert_eq!(indices_3d[1].shape(), vec![1, 2, 1]);
assert_eq!(indices_3d[2].shape(), vec![1, 1, 1]);
let empty_indices = ix_::<i32>(&[]).expect("operation should succeed");
assert_eq!(empty_indices.len(), 0);
let bad_array = Array::from_vec(vec![1, 2, 3, 4]).reshape(&[2, 2]);
let result = ix_(&[&bad_array]);
assert!(result.is_err());
}
}