如何(如果可能)在 Rust 中按值对 BTreeMap 进行排序?
How (if possible) to sort a BTreeMap by value in Rust?
我正在学习软件安全课程,其中一项作业是用 Rust 编写一些基本程序。对于其中一项作业,我需要分析一个文本文件并生成多个统计数据。其中之一是文本中最常用的十个单词的生成列表。
我写了this program,它执行作业中除了上面提到的词频统计之外的所有任务,程序编译和执行的方式符合我的预期:
extern crate regex;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::io::BufReader;
use std::collections::BTreeMap;
use regex::Regex;
fn main() {
// Create a path to the desired file
let path = Path::new("text.txt");
let display = path.display();
let file = match File::open(&path) {
Err(why) => panic!("couldn't open {}: {}", display,
why.description()),
Ok(file) => file,
};
let mut wordcount = 0;
let mut averagesize = 0;
let mut wordsize = BTreeMap::new();
let mut words = BTreeMap::new();
for line in (BufReader::new(file)).lines() {
let re = Regex::new(r"([A-Za-z]+[-_]*[A-Za-z]+)+").unwrap();
for cap in re.captures_iter(&line.unwrap()) {
let word = cap.at(1).unwrap_or("");
let lower = word.to_lowercase();
let s = lower.len();
wordcount += 1;
averagesize += s;
*words.entry(lower).or_insert(0) += 1;
*wordsize.entry(s).or_insert(0) += 1;
}
}
averagesize = averagesize / wordcount;
println!("This file contains {} words with an average of {} letters per word.", wordcount, averagesize);
println!("\nThe number of times a word of a certain length was found.");
for (size, count) in wordsize.iter() {
println!("There are {} words of size {}.", count, size);
}
println!("\nThe ten most used words.");
let mut popwords = BTreeMap::new();
for (word, count) in words.iter() {
if !popwords.contains_key(count) {
popwords.insert(count, "");
}
let newstring = format!("{} {}", popwords.get(count), word);
let mut e = popwords.get_mut(count);
}
let mut i = 0;
for (count, words) in popwords.iter() {
i += 1;
if i > 10 {
break;
}
println!("{} times: {}", count, words);
}
}
我有一个 BTreeMap
(我用 these 指令选择的),words
,它将每个单词存储为键,并将其在文本中的相关频率存储为值。此功能按我的预期工作,但我被困在那里。我一直在尝试寻找按值对 BTreemap
进行排序的方法,或者在 Rust 中找到另一个按值本机排序的数据结构。
我正在寻找在 Rust 中实现此数据结构(按频率排序的单词及其频率的列表)的正确方法。非常感谢任何指点!
如果你只需要分析静态数据集,最简单的方法就是最后将你的BTreeMap
转换成Vec<T>
并对后者进行排序(Playground):
use std::iter::FromIterator;
let mut v = Vec::from_iter(map);
v.sort_by(|&(_, a), &(_, b)| b.cmp(&a));
向量包含 (key, value)
对作为元组。要对向量进行排序,我们必须使用 sort_by()
或 sort_by_key()
。为了按降序对向量进行排序,我使用了 b.cmp(&a)
(与 a.cmp(&b)
相反,后者是自然顺序)。但是有.
但是,如果你真的需要一些数据结构来进行流式计算,那就更复杂了。在这种情况下有很多可能性,但我想使用某种优先级队列可能会奏效。
我正在学习软件安全课程,其中一项作业是用 Rust 编写一些基本程序。对于其中一项作业,我需要分析一个文本文件并生成多个统计数据。其中之一是文本中最常用的十个单词的生成列表。
我写了this program,它执行作业中除了上面提到的词频统计之外的所有任务,程序编译和执行的方式符合我的预期:
extern crate regex;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::io::BufReader;
use std::collections::BTreeMap;
use regex::Regex;
fn main() {
// Create a path to the desired file
let path = Path::new("text.txt");
let display = path.display();
let file = match File::open(&path) {
Err(why) => panic!("couldn't open {}: {}", display,
why.description()),
Ok(file) => file,
};
let mut wordcount = 0;
let mut averagesize = 0;
let mut wordsize = BTreeMap::new();
let mut words = BTreeMap::new();
for line in (BufReader::new(file)).lines() {
let re = Regex::new(r"([A-Za-z]+[-_]*[A-Za-z]+)+").unwrap();
for cap in re.captures_iter(&line.unwrap()) {
let word = cap.at(1).unwrap_or("");
let lower = word.to_lowercase();
let s = lower.len();
wordcount += 1;
averagesize += s;
*words.entry(lower).or_insert(0) += 1;
*wordsize.entry(s).or_insert(0) += 1;
}
}
averagesize = averagesize / wordcount;
println!("This file contains {} words with an average of {} letters per word.", wordcount, averagesize);
println!("\nThe number of times a word of a certain length was found.");
for (size, count) in wordsize.iter() {
println!("There are {} words of size {}.", count, size);
}
println!("\nThe ten most used words.");
let mut popwords = BTreeMap::new();
for (word, count) in words.iter() {
if !popwords.contains_key(count) {
popwords.insert(count, "");
}
let newstring = format!("{} {}", popwords.get(count), word);
let mut e = popwords.get_mut(count);
}
let mut i = 0;
for (count, words) in popwords.iter() {
i += 1;
if i > 10 {
break;
}
println!("{} times: {}", count, words);
}
}
我有一个 BTreeMap
(我用 these 指令选择的),words
,它将每个单词存储为键,并将其在文本中的相关频率存储为值。此功能按我的预期工作,但我被困在那里。我一直在尝试寻找按值对 BTreemap
进行排序的方法,或者在 Rust 中找到另一个按值本机排序的数据结构。
我正在寻找在 Rust 中实现此数据结构(按频率排序的单词及其频率的列表)的正确方法。非常感谢任何指点!
如果你只需要分析静态数据集,最简单的方法就是最后将你的BTreeMap
转换成Vec<T>
并对后者进行排序(Playground):
use std::iter::FromIterator;
let mut v = Vec::from_iter(map);
v.sort_by(|&(_, a), &(_, b)| b.cmp(&a));
向量包含 (key, value)
对作为元组。要对向量进行排序,我们必须使用 sort_by()
或 sort_by_key()
。为了按降序对向量进行排序,我使用了 b.cmp(&a)
(与 a.cmp(&b)
相反,后者是自然顺序)。但是有
但是,如果你真的需要一些数据结构来进行流式计算,那就更复杂了。在这种情况下有很多可能性,但我想使用某种优先级队列可能会奏效。