是否有更简洁或声明性的方式来初始化 HashMap?
Is there a more concise or declarative way to initialize a HashMap?
我正在使用 HashMap
来计算字符串中不同字符的出现次数:
let text = "GATTACA";
let mut counts: HashMap<char, i32> = HashMap::new();
counts.insert('A', 0);
counts.insert('C', 0);
counts.insert('G', 0);
counts.insert('T', 0);
for c in text.chars() {
match counts.get_mut(&c) {
Some(x) => *x += 1,
None => (),
}
}
是否有更简洁或声明性的方式来初始化 HashMap
?例如在 Python 我会做:
counts = { 'A': 0, 'C': 0, 'G': 0, 'T': 0 }
或
counts = { key: 0 for key in 'ACGT' }
您可以使用迭代器来模拟字典理解,例如
let counts = "ACGT".chars().map(|c| (c, 0_i32)).collect::<HashMap<_, _>>();
甚至for c in "ACGT".chars() { counts.insert(c, 0) }
.
此外,可以编写一个宏来允许对任意值进行简洁的初始化。
macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $val); )*
map
}}
}
像 let counts = hashmap!['A' => 0, 'C' => 0, 'G' => 0, 'T' => 0];
一样使用。
我在 official documentation 中看到的另一种方式:
use std::collections::HashMap;
fn main() {
let timber_resources: HashMap<&str, i32> =
[("Norway", 100),
("Denmark", 50),
("Iceland", 10)]
.iter().cloned().collect();
// use the values stored in map
}
编辑
当我再次访问官方文档时,我看到示例已更新(旧示例已删除)。所以这是 Rust 1.56 的最新解决方案:
let vikings = HashMap::from([
("Norway", 25),
("Denmark", 24),
("Iceland", 12),
]);
这种(非常常见的)情况就是为什么我在发现 Python 的 defaultdict 时听到天使歌唱的原因,这是一本字典,如果您尝试获取密钥如果不在字典中,则立即 创建 使用您在声明 defaultdict 时提供的构造函数为该键创建一个默认值。因此,在 Python 中,您可以执行以下操作:
counts = defaultdict(lambda: 0)
counts['A'] = counts['A'] + 1
对于计算出现次数,这是最受欢迎的方法,因为当键空间很大或程序员不知道时,尝试预填充散列表会出现问题(想象一下对您提供给它的文本中的单词进行计数的东西。你是要预先填充所有英文单词吗?如果一个新单词进入词典怎么办?)。
您可以使用 选项 class 中鲜为人知的方法在 Rust 中实现相同的目的。说真的,当你有空的时候,通读一下 Option 中的所有方法。里面有一些非常好用的方法。
虽然没有处理简洁的初始化(这是 wubject 所要求的),但这里有两个答案(可以说,它们更适合做 OP 试图做的事情)。
let text = "GATTACA";
let mut counts:HashMap<char,i32> = HashMap::new();
for c in text.chars() {
counts.insert(c,*(counts.get(&c).get_or_insert(&0))+1);
}
上述方法使用 Option 的 get 或 insert() 方法,如果它是 Some(),returns 值,如果是 None, return 是您提供的值。 请注意,即使该方法名为 get_or_insert(),它也是 而不是 插入到 hashmap 中;这是 Option 的一个方法,hashmap 不知道这个故障转移正在发生。好的一点是,这会为您解开价值。这与 Python 的 defaultdict 非常相似,不同之处在于您必须在代码的多个位置提供默认值(引发错误,但也提供了 defaultdict 缺乏的额外灵活性)。
let text = "GATTACA";
let mut counts:HashMap<char,i32> = HashMap::new();
for c in text.chars() {
counts.insert(c,counts.get(&c).or_else(|| Some(&0)).unwrap()+1);
}
此方法使用 Option 的 or else() 方法,该方法允许您指定用于生成值的 lambda,并且最重要的是,让您 still return a None (想象一下,如果你想检查一个散列映射中的一个键,如果没有找到,检查 另一个 散列映射,并且,只有当两者都没有找到,您是否制作了 None)。因为 or else() return 是一个选项,我们必须使用 unwrap() (如果在 None,但我们知道这不适用于此处)。
从 Rust 1.56 开始,您可以使用 from()
从键值对数组构建 Hashmap
。这使得无需指定类型或编写宏就可以简洁地进行初始化。
use std::collections::HashMap;
fn main() {
let m = HashMap::from([
('A', 0),
('C', 0),
('G', 0),
('T', 0)
]);
}
我正在使用 HashMap
来计算字符串中不同字符的出现次数:
let text = "GATTACA";
let mut counts: HashMap<char, i32> = HashMap::new();
counts.insert('A', 0);
counts.insert('C', 0);
counts.insert('G', 0);
counts.insert('T', 0);
for c in text.chars() {
match counts.get_mut(&c) {
Some(x) => *x += 1,
None => (),
}
}
是否有更简洁或声明性的方式来初始化 HashMap
?例如在 Python 我会做:
counts = { 'A': 0, 'C': 0, 'G': 0, 'T': 0 }
或
counts = { key: 0 for key in 'ACGT' }
您可以使用迭代器来模拟字典理解,例如
let counts = "ACGT".chars().map(|c| (c, 0_i32)).collect::<HashMap<_, _>>();
甚至for c in "ACGT".chars() { counts.insert(c, 0) }
.
此外,可以编写一个宏来允许对任意值进行简洁的初始化。
macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $val); )*
map
}}
}
像 let counts = hashmap!['A' => 0, 'C' => 0, 'G' => 0, 'T' => 0];
一样使用。
我在 official documentation 中看到的另一种方式:
use std::collections::HashMap;
fn main() {
let timber_resources: HashMap<&str, i32> =
[("Norway", 100),
("Denmark", 50),
("Iceland", 10)]
.iter().cloned().collect();
// use the values stored in map
}
编辑
当我再次访问官方文档时,我看到示例已更新(旧示例已删除)。所以这是 Rust 1.56 的最新解决方案:
let vikings = HashMap::from([
("Norway", 25),
("Denmark", 24),
("Iceland", 12),
]);
这种(非常常见的)情况就是为什么我在发现 Python 的 defaultdict 时听到天使歌唱的原因,这是一本字典,如果您尝试获取密钥如果不在字典中,则立即 创建 使用您在声明 defaultdict 时提供的构造函数为该键创建一个默认值。因此,在 Python 中,您可以执行以下操作:
counts = defaultdict(lambda: 0)
counts['A'] = counts['A'] + 1
对于计算出现次数,这是最受欢迎的方法,因为当键空间很大或程序员不知道时,尝试预填充散列表会出现问题(想象一下对您提供给它的文本中的单词进行计数的东西。你是要预先填充所有英文单词吗?如果一个新单词进入词典怎么办?)。
您可以使用 选项 class 中鲜为人知的方法在 Rust 中实现相同的目的。说真的,当你有空的时候,通读一下 Option 中的所有方法。里面有一些非常好用的方法。
虽然没有处理简洁的初始化(这是 wubject 所要求的),但这里有两个答案(可以说,它们更适合做 OP 试图做的事情)。
let text = "GATTACA";
let mut counts:HashMap<char,i32> = HashMap::new();
for c in text.chars() {
counts.insert(c,*(counts.get(&c).get_or_insert(&0))+1);
}
上述方法使用 Option 的 get 或 insert() 方法,如果它是 Some(),returns 值,如果是 None, return 是您提供的值。 请注意,即使该方法名为 get_or_insert(),它也是 而不是 插入到 hashmap 中;这是 Option 的一个方法,hashmap 不知道这个故障转移正在发生。好的一点是,这会为您解开价值。这与 Python 的 defaultdict 非常相似,不同之处在于您必须在代码的多个位置提供默认值(引发错误,但也提供了 defaultdict 缺乏的额外灵活性)。
let text = "GATTACA";
let mut counts:HashMap<char,i32> = HashMap::new();
for c in text.chars() {
counts.insert(c,counts.get(&c).or_else(|| Some(&0)).unwrap()+1);
}
此方法使用 Option 的 or else() 方法,该方法允许您指定用于生成值的 lambda,并且最重要的是,让您 still return a None (想象一下,如果你想检查一个散列映射中的一个键,如果没有找到,检查 另一个 散列映射,并且,只有当两者都没有找到,您是否制作了 None)。因为 or else() return 是一个选项,我们必须使用 unwrap() (如果在 None,但我们知道这不适用于此处)。
从 Rust 1.56 开始,您可以使用 from()
从键值对数组构建 Hashmap
。这使得无需指定类型或编写宏就可以简洁地进行初始化。
use std::collections::HashMap;
fn main() {
let m = HashMap::from([
('A', 0),
('C', 0),
('G', 0),
('T', 0)
]);
}