如何有效地将任意函数应用于 BTreeMap 中的移动 window
How to efficiently apply an arbitrary function on a moving window in a BTreeMap
如何有效地将函数应用于 BTreeMap
的移动 window,其中 window 由键的范围决定?
我当前的代码是这样的,但是当 BTreeMap
变得非常大时(并且可能随着 radius
的增加),它会非常慢。我怀疑这是因为 clone()
但我想不出替代解决方案。我如何有效地做到这一点?
use nalgebra::Vector3;
use std::collections::BTreeMap;
fn get_window(data: &BTreeMap<i64, Vector3<f64>>, center: &i64, radius: &i64) -> BTreeMap<i64, Vector3<f64>> {
let mut window = data.clone();
window.retain(|&ts, _| ts >= (center - radius) && ts <= (center + radius));
window
}
fn kernel(data: BTreeMap<i64, Vector3<f64>>) -> Vector3<f64> {
// This is just an example function
let n = data.len() as f64;
let x = data.iter().map(|(_, vec)| vec[0]).sum::<f64>() / n;
let y = data.iter().map(|(_, vec)| vec[1]).sum::<f64>() / n;
let z = data.iter().map(|(_, vec)| vec[2]).sum::<f64>() / n;
Vector3::new(x, y, z)
}
fn main() {
let mut btreemap = BTreeMap::<i64, Vector3<f64>>::new();
btreemap.insert(0, Vector3::new(0.0, 0.0, 0.0));
btreemap.insert(1, Vector3::new(1.0, 0.0, 0.0));
btreemap.insert(2, Vector3::new(0.0, 1.0, 0.0));
btreemap.insert(3, Vector3::new(0.0, 0.0, 1.0));
btreemap.insert(4, Vector3::new(2.0, 0.0, 0.0));
btreemap.insert(5, Vector3::new(0.0, 2.0, 0.0));
btreemap.insert(6, Vector3::new(0.0, 0.0, 2.0));
let mut smoothed = BTreeMap::<i64, Vector3<f64>>::new();
for (ts, _vec) in btreemap.iter() {
let window = get_window(&btreemap, &ts, &1);
let kernel = kernel(window);
smoothed.insert(*ts, kernel);
}
println!("{:?}", smoothed);
}
您可以使用 BTreeMap::range
to get an iterator over the items within a range of the map. This is cheap because a btree_map::Range
迭代源地图中的数据,而不是克隆地图然后过滤 window 中的项目;它不会克隆任何内容。
我还建议将中心和半径作为 i64
而不是 &i64
传递。不用借了。
use std::collections::BTreeMap;
use std::collections::btree_map;
fn get_window(data: &BTreeMap<i64, Vector3<f64>>, center: i64, radius: i64) -> btree_map::Range<'_, i64, Vector3<f64>> {
data.range(center-radius..=center+radius)
}
fn kernel(data: btree_map::Range<'_, i64, Vector3<f64>>) -> Vector3<f64> {
// This is just an example function
let n = data.clone().count() as f64;
let x = data.clone().map(|(_, vec)| vec[0]).sum::<f64>() / n;
let y = data.clone().map(|(_, vec)| vec[1]).sum::<f64>() / n;
let z = data.clone().map(|(_, vec)| vec[2]).sum::<f64>() / n;
Vector3::new(x, y, z)
}
main
中的循环变为:
for (&ts, _vec) in btreemap.iter() {
let window = get_window(&btreemap, ts, 1);
let kernel = kernel(window);
smoothed.insert(ts, kernel);
}
如何有效地将函数应用于 BTreeMap
的移动 window,其中 window 由键的范围决定?
我当前的代码是这样的,但是当 BTreeMap
变得非常大时(并且可能随着 radius
的增加),它会非常慢。我怀疑这是因为 clone()
但我想不出替代解决方案。我如何有效地做到这一点?
use nalgebra::Vector3;
use std::collections::BTreeMap;
fn get_window(data: &BTreeMap<i64, Vector3<f64>>, center: &i64, radius: &i64) -> BTreeMap<i64, Vector3<f64>> {
let mut window = data.clone();
window.retain(|&ts, _| ts >= (center - radius) && ts <= (center + radius));
window
}
fn kernel(data: BTreeMap<i64, Vector3<f64>>) -> Vector3<f64> {
// This is just an example function
let n = data.len() as f64;
let x = data.iter().map(|(_, vec)| vec[0]).sum::<f64>() / n;
let y = data.iter().map(|(_, vec)| vec[1]).sum::<f64>() / n;
let z = data.iter().map(|(_, vec)| vec[2]).sum::<f64>() / n;
Vector3::new(x, y, z)
}
fn main() {
let mut btreemap = BTreeMap::<i64, Vector3<f64>>::new();
btreemap.insert(0, Vector3::new(0.0, 0.0, 0.0));
btreemap.insert(1, Vector3::new(1.0, 0.0, 0.0));
btreemap.insert(2, Vector3::new(0.0, 1.0, 0.0));
btreemap.insert(3, Vector3::new(0.0, 0.0, 1.0));
btreemap.insert(4, Vector3::new(2.0, 0.0, 0.0));
btreemap.insert(5, Vector3::new(0.0, 2.0, 0.0));
btreemap.insert(6, Vector3::new(0.0, 0.0, 2.0));
let mut smoothed = BTreeMap::<i64, Vector3<f64>>::new();
for (ts, _vec) in btreemap.iter() {
let window = get_window(&btreemap, &ts, &1);
let kernel = kernel(window);
smoothed.insert(*ts, kernel);
}
println!("{:?}", smoothed);
}
您可以使用 BTreeMap::range
to get an iterator over the items within a range of the map. This is cheap because a btree_map::Range
迭代源地图中的数据,而不是克隆地图然后过滤 window 中的项目;它不会克隆任何内容。
我还建议将中心和半径作为 i64
而不是 &i64
传递。不用借了。
use std::collections::BTreeMap;
use std::collections::btree_map;
fn get_window(data: &BTreeMap<i64, Vector3<f64>>, center: i64, radius: i64) -> btree_map::Range<'_, i64, Vector3<f64>> {
data.range(center-radius..=center+radius)
}
fn kernel(data: btree_map::Range<'_, i64, Vector3<f64>>) -> Vector3<f64> {
// This is just an example function
let n = data.clone().count() as f64;
let x = data.clone().map(|(_, vec)| vec[0]).sum::<f64>() / n;
let y = data.clone().map(|(_, vec)| vec[1]).sum::<f64>() / n;
let z = data.clone().map(|(_, vec)| vec[2]).sum::<f64>() / n;
Vector3::new(x, y, z)
}
main
中的循环变为:
for (&ts, _vec) in btreemap.iter() {
let window = get_window(&btreemap, ts, 1);
let kernel = kernel(window);
smoothed.insert(ts, kernel);
}