2016-12-19 2 views
1

나는 Rust에서 몇 가지 기본 프로그램을 작성하는 과제 중 하나에 대해 Software Security 과정을 수강 중입니다. 이러한 과제 중 하나의 경우 텍스트 파일을 분석하고 여러 통계를 생성해야합니다. 이 중 하나는 텍스트에서 가장 많이 사용 된 10 개의 단어 목록입니다. 나는이 프로그램을 컴파일하고 내가 예상 한대로 실행, 위에서 언급 한 단어 빈도 통계를 제외하고 할당의 모든 작업을 수행 this program를 작성했습니다(가능한 경우) Rust에서 값으로 BTreeMap을 정렬 하시겠습니까?

:

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을 분류하는 방법을 찾거나 값에 의해 기본적으로 정렬되는 녹의 다른 데이터 구조를 찾으려고 노력 해왔다.

나는 녹이에서이 데이터 구조 (빈도로 정렬 된 단어 목록)를 얻는 올바른 방법을 찾고 있습니다. 모든 포인터 크게 감사하겠습니다! 당신은 단지 정적 데이터 세트를 분석해야하는 경우

+2

word * 및 * 값으로 인덱싱해야하는 경우 두 데이터 구조 (마치 랩핑되었을 수 있음)처럼 들립니다. 아마도 BTreeMap 또는 HashMap에 카운트를 쌓은 다음 끝에 Vec으로 바꿀 것이라고 생각합니다. –

+2

관심 없어, 코스/코스는 어디입니까? –

+0

@ChrisEmerson 그것은 네덜란드의 4TU 마스터 사이버 보안 프로그램의 일환으로, 트벤테 대학교와 델프트 대학교의 공동 프로그램으로 첫 번째 대학을 통해 참석합니다. – Jonathan

답변

2

, 가장 쉬운 방법은 (Playground를) 변환 당신의 말에 Vec<T>BTreeMap 후자를 정렬하는 것입니다

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)을 사용했습니다. 이는 자연 순서입니다. 그러나 other possibilities to reverse the order of a sort이 있습니다.


그러나 실제로 스트리밍 계산과 같은 일부 데이터 구조가 필요한 경우 더 복잡해집니다. 이 경우에는 여러 가지 가능성이 있지만 우선 순위 대기열을 사용하면 문제가 해결 될 수 있습니다.

+0

이것은 내 문제에 대한 해결책 인 것 같습니다. 나는이 방법으로 벡터를 사용할 수 있다는 것을 결코 깨닫지 못했습니다. 나는 곧바로 그것을 시도 할 것이다. – Jonathan

+0

부정하는 대신 [the revord crate] (http://stackoverflow.com/q/40369255/155423)를 사용하는 것이 좋습니다. -MIN_INT는 표현할 수 없습니다. – Shepmaster

+0

@Shepmaster 나는이 문제를 해결하기 위해'wordlenghts.insert (word.to_lowercase(), word.chars(). count()를 i64로 사용하여 부호있는 정수로 명시 적으로 선언한다. 팁을 가져 주셔서 감사합니다. – Jonathan

관련 문제