在Rust中如何获取两个向量重叠元素的索引?
在Rust中如何获取两个向量重叠元素的索引?
嘿,我完全懂你的需求——找两个向量里相同元素各自的索引对吧?确实Rust标准库没有直接提供overlaps这样的方法,但咱们用标准库的工具就能组合出简洁又高效的实现,不用折腾那些又大又难用的自定义函数~
最地道的做法是借助哈希表先建立“元素-索引”的映射,然后用迭代器快速筛选出重叠元素的索引,这样时间复杂度是O(n+m),比双重循环的O(n*m)高效太多,尤其是向量规模大的时候。
基础实现(元素唯一的情况)
先看针对你给出的例子的实现,刚好你的元素都是唯一的:
fn main() { let my_vector1 = ["snake", "bird", "fish", "cat", "dog"]; let my_vector2 = ["tiger", "cat", "bear", "dog", "coyote"]; // 先把第二个向量的元素和对应索引存成哈希表,方便O(1)查找 let vec2_index_map: std::collections::HashMap<_, _> = my_vector2.iter().enumerate().map(|(idx, val)| (val, idx)).collect(); // 筛选出vec1中在vec2里存在的元素的索引 let values1: Vec<usize> = my_vector1 .iter() .enumerate() .filter(|(_, val)| vec2_index_map.contains_key(val)) .map(|(idx, _)| idx) .collect(); // 反过来处理vec2的情况 let vec1_index_map: std::collections::HashMap<_, _> = my_vector1.iter().enumerate().map(|(idx, val)| (val, idx)).collect(); let values2: Vec<usize> = my_vector2 .iter() .enumerate() .filter(|(_, val)| vec1_index_map.contains_key(val)) .map(|(idx, _)| idx) .collect(); println!("values1: {:?}", values1); // 输出 [3, 4] println!("values2: {:?}", values2); // 输出 [1, 3] }
封装成通用函数
如果需要多次复用这个逻辑,可以把它封装成一个通用函数,支持任何可哈希、可比较的元素类型:
use std::collections::HashMap; // 获取第一个向量中,在第二个向量里存在的元素的索引 fn overlapping_indices<T: Eq + std::hash::Hash>(source: &[T], target: &[T]) -> Vec<usize> { let target_index_map: HashMap<_, _> = target.iter().enumerate().map(|(idx, val)| (val, idx)).collect(); source .iter() .enumerate() .filter(|(_, val)| target_index_map.contains_key(val)) .map(|(idx, _)| idx) .collect() } fn main() { let my_vector1 = ["snake", "bird", "fish", "cat", "dog"]; let my_vector2 = ["tiger", "cat", "bear", "dog", "coyote"]; let values1 = overlapping_indices(&my_vector1, &my_vector2); let values2 = overlapping_indices(&my_vector2, &my_vector1); println!("values1: {:?}", values1); // [3, 4] println!("values2: {:?}", values2); // [1, 3] }
处理元素重复的情况
如果你的向量里有重复元素(比如vec2里有多个"cat"),上面的方法只会保留最后一个元素的索引。要是需要收集所有匹配的索引,可以把哈希表的值改成向量:
use std::collections::HashMap; // 获取第一个向量中每个元素,在第二个向量里对应的所有索引 fn all_overlapping_indices<T: Eq + std::hash::Hash>(source: &[T], target: &[T]) -> Vec<(usize, Vec<usize>)> { let mut target_index_map: HashMap<_, Vec<usize>> = HashMap::new(); for (idx, val) in target.iter().enumerate() { target_index_map.entry(val).or_default().push(idx); } source .iter() .enumerate() .filter_map(|(src_idx, val)| { target_index_map.get(val).map(|target_indices| (src_idx, target_indices.clone())) }) .collect() } fn main() { let my_vector1 = ["cat", "dog", "cat"]; let my_vector2 = ["tiger", "cat", "bear", "dog", "cat"]; let result = all_overlapping_indices(&my_vector1, &my_vector2); println!("{:?}", result); // 输出 [(0, [1, 4]), (1, [3]), (2, [1, 4])] }
这种写法完全符合Rust的迭代器风格,代码简洁又高效,比自己手写嵌套循环靠谱多啦~
内容来源于stack exchange
相关产品推荐
相关产品推荐

