关于rust:按值对HashMap数据进行排序

Sort HashMap data by value

我想按Rust中的值对HashMap数据进行排序(例如,当计算字符串中的字符频率时)。

我想要做的Python等效项是:

1
2
3
4
5
6
7
count = {}
for c in text:
    count[c] = count.get('c', 0) + 1

sorted_data = sorted(count.items(), key=lambda item: -item[1])

print('Most frequent character in text:', sorted_data[0][0])

我相应的Rust代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
// Count the frequency of each letter
let mut count: HashMap<char, u32> = HashMap::new();
for c in text.to_lowercase().chars() {
    *count.entry(c).or_insert(0) += 1;
}

// Get a sorted (by field 0 ("count") in reversed order) list of the
// most frequently used characters:
let mut count_vec: Vec<(&char, &u32)> = count.iter().collect();
count_vec.sort_by(|a, b| b.1.cmp(a.1));

println!("Most frequent character in text: {}", count_vec[0].0);

这是惯用的Rust吗?我是否可以以某种方式构造count_vec,以便它可以使用HashMaps数据并拥有该数据(例如,使用map())?这会更像偶像吗?


Is this idiomatic Rust?

没有什么特别独特的,除了可能对count_vec的不必要的全类型约束;你可以只用

1
let mut count_vec: Vec<_> = count.iter().collect();

根据上下文确定count_vec的完整类型并不难。您也可以完全省略count的类型约束,但随后您必须使用整数文字来玩弄恶作剧,才能推断出正确的值类型。也就是说,在这种情况下,显式注释非常合理。

如果您感觉要使用|a, b| a.1.cmp(b.1).reverse()进行排序关闭,则可以进行其他边界更改。 Ordering::reverse方法只是将结果取反,因此小于等于变为大于,反之亦然。这使您更清楚地表明了您的意思,而不是不小心调换了两个字母。

Can I construct the count_vec in a way so that it would consume the HashMaps data and owns it?

没有任何有意义的方式。仅仅因为HashMap正在使用内存并不意味着内存与Vec在任何方面都是兼容的。您可以使用count.into_iter()消耗HashMap并将元素移出(而不是遍历指针),但是由于charu32都是可复制的,因此并不能真正为您带来任何好处。


这可能是解决此问题的另一种方式,而无需中间媒介。

1
2
3
4
5
6
7
8
9
// Count the frequency of each letter
let mut count: HashMap<char, u32> = HashMap::new();
for c in text.to_lowercase().chars() {
    *count.entry(c).or_insert(0) += 1;
}

let top_char = count.iter().max_by(|a, b| a.1.cmp(&b.1)).unwrap();

println!("Most frequent character in text: {}", top_char.0);