use opendp_derive::bootstrap;
use crate::{
core::{Function, StabilityMap, Transformation},
error::Fallible,
metrics::SymmetricDistance,
traits::Hashable,
};
use super::{DataFrame, DataFrameDomain};
#[cfg(feature = "ffi")]
mod ffi;
#[bootstrap(features("contrib"))]
pub fn make_subset_by<TK: Hashable>(
indicator_column: TK,
keep_columns: Vec<TK>,
) -> Fallible<
Transformation<DataFrameDomain<TK>, DataFrameDomain<TK>, SymmetricDistance, SymmetricDistance>,
> {
Transformation::new(
DataFrameDomain::new(),
DataFrameDomain::new(),
Function::new_fallible(move |data: &DataFrame<TK>| {
let indicator = (data.get(&indicator_column))
.ok_or_else(|| err!(FailedFunction, "{:?} does not exist in the input dataframe"))?
.as_form::<Vec<bool>>()?;
let mut subsetted = DataFrame::new();
keep_columns.iter().try_for_each(|column_name| {
let column = data.get(&column_name).ok_or_else(|| {
err!(FailedFunction, "{:?} does not exist in the input dataframe")
})?;
subsetted.insert(column_name.clone(), column.subset(&indicator));
Fallible::Ok(())
})?;
Ok(subsetted)
}),
SymmetricDistance::default(),
SymmetricDistance::default(),
StabilityMap::new_from_constant(1),
)
}
#[cfg(test)]
mod test {
use crate::error::ExplainUnwrap;
use super::*;
#[test]
fn test_subset_by() -> Fallible<()> {
let trans = make_subset_by::<String>("filter".to_string(), vec!["values".to_string()])?;
let mut df = DataFrame::new();
df.insert("filter".to_string(), vec![true, false, false, true].into());
df.insert("values".to_string(), vec!["1", "2", "3", "4"].into());
let res = trans.invoke(&df)?;
let subset = res
.get("values")
.unwrap_test()
.as_form::<Vec<&str>>()?
.clone();
assert_eq!(subset, vec!["1", "4"]);
Ok(())
}
}