hashset
hashset说明
天然去除重复元素
创建和初始化
new
use std::collections::HashSet;
fn main() {
let mut set = HashSet::new();
}
查看容量和长度
use std::collections::HashSet;
fn main() {
let mut set: HashSet<i32> = HashSet::new();
println!("初始容量: {}", set.capacity());
println!("长度: {}", set.len());
println!("是否为空: {}", set.is_empty());
// 添加一些元素后再看容量
set.insert(1);
println!("插入1个元素后的容量: {}", set.capacity());
set.insert(2);
set.insert(3);
println!("插入3个元素后的容量: {}", set.capacity());
println!("长度: {}", set.len());
}
初始容量: 0
长度: 0
是否为空: true
插入1个元素后的容量: 3
插入3个元素后的容量: 3
长度: 3
with_capacity
使用
with_capacity预分配容量(性能优化)
use std::collections::HashSet;
fn main() {
let mut set = HashSet::with_capacity(10);
}
请求容量测试
use std::collections::HashSet;
fn main() {
for requested in [1, 5, 10, 16, 20, 32] {
let s: HashSet<i32> = HashSet::with_capacity(requested);
println!("请求: {}, 实际: {}", requested, s.capacity());
}
}
请求: 1, 实际: 3
请求: 5, 实际: 7
请求: 10, 实际: 14
请求: 16, 实际: 28
请求: 20, 实际: 28
请求: 32, 实际: 56
数组/vec创建
use std::collections::HashSet;
fn main() {
// 方式一: 使用from创建
let set = HashSet::from([1, 2, 3]);
// 方式二: 使用数组字面量创建
let set: HashSet<_> = [1, 2, 3, 4].iter().cloned().collect();
// Vec创建
let v = vec![1, 2, 3];
let set = HashSet::from(v); // v因为所有权已被转移
}
元组创建
需要展开为数组
use std::collections::HashSet;
fn main() {
let t = (1, 2, 3);
// 方式一
let set: HashSet<i32> = [t.0, t.1, t.2].iter().cloned().collect();
// 方式二
let set: HashSet<i32> = HashSet::from([t.0, t.1, t.2]);
}
切片创建
use std::collections::HashSet;
fn main() {
let slice: &[i32] = &[1, 2, 3, 4];
let set: HashSet<i32> = slice.iter().cloned().collect();
println!("{:?}", set)
}
操作元素
添加元素
insert会返回bool值,如果元素已经存在则返回false(添加失败)
use std::collections::HashSet;
fn main() {
let mut s = HashSet::new();
let is_add = s.insert("a");
println!("is_add: {}", is_add);
println!("s: {:?}", s);
}
is_add: true
s: {"a"}
批量添加
s.extend(iter), 就地修改s集合,不创建新集合
use std::collections::HashSet;
fn main() {
let mut s = HashSet::new();
s.extend(["a", "b", "c"]);
s.extend(["a", "b", "2222"]); // a和b存在,就不会添加,之后添加2222
println!("{:?}", s);
}
{"a", "b", "c", "2222"}
删除元素
s.remove(&value)返回bool值,如果元素不存在则返回false(删除失败)
use std::collections::HashSet;
fn main() {
let mut s1 = HashSet::from([1,2,3,4]);
let is_del = s1.remove(&23); // 删除23失败,不存在
println!("{}", is_del);
println!("{:?}", s1);
}
false
{1, 3, 2, 4}
条件删除
s.retain(|x| x % 2 == 0): 保留偶数
use std::collections::HashSet;
fn main() {
let mut s1 = HashSet::from([1,2,3,4]);
s1.retain(|&x| x % 2 == 0);
println!("{:?}", s1)
}
{4, 2}
消费元素
s.take(&value): 删除并返回元素,返回Option<T>
use std::collections::HashSet;
fn main() {
let mut s = HashSet::from([1,2,3,4]);
let v1 = s.take(&2);
println!("v1: {:?}", v1);
println!("s: {:?}", s);
let v2 = s.take(&22);
println!("v2: {:?}", v2);
}
v1: Some(2)
s: {1, 3, 4}
v2: None
查询
查询元素是否存在
set.contains(&value): 需要引用值
use std::collections::HashSet;
fn main() {
let s = HashSet::from([1,2,3,4]);
let exists1 = s.contains(&2);
println!("exists[2]: {}", exists1);
let exists2 = s.contains(&0);
println!("exists[0]: {}", exists2);
}
exists[2]: true
exists[0]: false
获取元素
set.get(&value): 需要引用值,返回一个Option<&T>
use std::collections::HashSet;
fn main() {
let mut s = HashSet::from([1,2,3,4]);
let v1 = s.get(&2);
println!("v1: {:?}", v1);
println!("s: {:?}", s);
let v2 = s.get(&22);
println!("v2: {:?}", v2);
}
v1: Some(2)
s: {3, 1, 2, 4}
v2: None
元素数量
set.len()
use std::collections::HashSet;
fn main() {
let s1 = HashSet::from([1,2,3,4]);
println!("s1: {}", s1.len());
let s2:HashSet<i32> = HashSet::new();
println!("s2: {}", s2.len());
}
s1: 4
s2: 0
set是否为空
set.is_empty()
use std::collections::HashSet;
fn main() {
let s1 = HashSet::from([1,2,3,4]);
println!("s1: {}", s1.is_empty());
let s2:HashSet<i32> = HashSet::new();
println!("s2: {}", s2.is_empty());
}
s1: false
s2: true
迭代
HashSet的迭代顺序是不确定的
迭代所有元素
use std::collections::HashSet;
fn main() {
let mut s = HashSet::from([1,2,3,4]);
// for i in &s
// i是&i32类型
for i in s.iter() {
println!("{}", i);
};
print!("{:?}", s)
}
1
3
4
2
{1, 3, 4, 2}%
获取所有权
use std::collections::HashSet;
fn main() {
let mut s = HashSet::from([1,2,3,4]);
// i是i32类型
for i in s.into_iter() {
println!("{}", i);
};
// print!("{:?}", s) // 不能再使用了,s已经被消费了
}
1
3
4
2
集合运算
union、intersection、difference、symmetric_difference,不会获取所有权.
它们接受引用参数&self和&other_set
交集
a.intersection(&b)表示a在b中的元素
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1,2,3]);
let b = HashSet::from([2,3,4]);
// 返回Intersection迭代器
let c = a.intersection(&b);
println!("{:?}", c);
// 迭代器转为集合
let c_set:HashSet<i32> = c.cloned().collect();
println!("{:?}", c_set);
}
[3, 2]
{2, 3}
并集
a.union(&b)表示a和b一起合并去重所有元素
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1,2,3]);
let b = HashSet::from([2,3,4]);
// 返回Union迭代器
let c = a.union(&b);
println!("{:?}", c);
// 迭代器转为集合
let c_set:HashSet<i32> = c.cloned().collect();
println!("{:?}", c_set);
}
[3, 1, 2, 4]
{2, 1, 3, 4}
差集
a.difference(&b)过滤出a没有在b中的元素
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1,2,3]);
let b = HashSet::from([2,3,4]);
// 返回Difference迭代器
let c = a.difference(&b);
println!("{:?}", c);
// 迭代器转为集合
let c_set:HashSet<i32> = c.cloned().collect();
println!("{:?}", c_set)
}
[1]
{1}
对称差集
a.symmetric_difference(&b)过滤出a和b中不重复的所有元素(包括b)
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1,2,3]);
let b = HashSet::from([2,3,4]);
// 返回SymmetricDifference迭代器
let c = a.symmetric_difference(&b);
println!("{:?}", c);
// 迭代器转为集合
let c_set:HashSet<i32> = c.cloned().collect();
println!("{:?}", c_set)
}
[1, 4]
{1, 4}
集合关系
子集
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1, 2, 3, 4, 5]);
let b = HashSet::from([2, 3, 4]);
// 返回bool迭代器
let s = b.is_subset(&a);
println!("b是a的子集: {}", s)
}
b是a的子集: true
超集
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1, 2, 3, 4, 5]);
let b = HashSet::from([2, 3, 4]);
// 返回bool迭代器
let s = a.is_superset(&b);
println!("a是b的超集: {}", s)
}
a是b的超集: true
不相交关系
两个集合没有公共元素
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1, 2, 3, 4, 5]);
let b = HashSet::from([21, 31, 41]);
// 返回bool迭代器
let s = a.is_disjoint(&b);
println!("a和b不相交: {}", s)
}
a和b不相交: true
相等
use std::collections::HashSet;
fn main() {
let a = HashSet::from([1, 2, 3, 4, 5]);
let b = HashSet::from([1, 2, 3, 4, 5]);
println!("a和b相等: {}", a == b);
}
a和b相等: true
自定义数据实现hash
HashSet需要元素实现
- Hash - 计算哈希值,快速定位桶位置
- PartialEq - 解决哈希冲突时比较是否真正相等
- Eq - 标记 trait,保证相等关系的数学性质
use std::hash::{Hash, Hasher};
use std::collections::HashSet;
#[derive(Debug)]
struct Key {
id: u32,
name: String,
}
// 必须实现 Hash
impl Hash for Key {
fn hash<H: Hasher>(&self, state: &mut H) {
println!(" Hash::hash called for {:?}", self);
self.id.hash(state);
self.name.hash(state);
}
}
// 必须实现 PartialEq
impl PartialEq for Key {
fn eq(&self, other: &Self) -> bool {
println!(" PartialEq::eq called: {:?} vs {:?}", self, other);
self.id == other.id && self.name == other.name
}
}
// 必须实现 Eq(标记 trait)
impl Eq for Key {}
fn main() {
let mut map = HashSet::new();
println!("Inserting first key:");
let key1 = Key { id: 1, name: "Alice".to_string() };
map.insert(key1);
let key2 = Key { id: 1, name: "Alice Modified".to_string() };
map.insert(key2);
println!("set: {:?}", map);
}
Inserting first key:
Hash::hash called for Key { id: 1, name: "Alice" }
Hash::hash called for Key { id: 1, name: "Alice Modified" }
set: {Key { id: 1, name: "Alice Modified" }, Key { id: 1, name: "Alice" }}

浙公网安备 33010602011771号