이 시리즈는 Rust 공식문서를 통해 공부한 흔적임을 밝힙니다.
이번 포스팅은 약간 번외편이다.
🦀 Ferris | "피터피터피터어ㅓㅓㅓㅓ!"
Here are some exercises you should now be equipped to solve:
- Given a list of integers, use a vector and return the mean (the average value), median (when sorted, the value in the middle position), and mode (the value that occurs most often; a hash map will be helpful here) of the list.
- Convert strings to pig latin. The first consonant of each word is moved to the end of the word and “ay” is added, so “first” becomes “irst-fay.” Words that start with a vowel have “hay” added to the end instead (“apple” becomes “apple-hay”). Keep in mind the details about UTF-8 encoding!
- Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in a company. For example, “Add Sally to Engineering” or “Add Amir to Sales.” Then let the user retrieve a list of all people in a department or all people in the company by department, sorted alphabetically.
🐧 Peter | "뭐야, 이 장황한 건... 그러니까 지금 나보고 이걸 구현해보라는 거지?"
그렇게 피터와 페리스는 이번에 Rust 공식문서에서 소개해준 작은 프로젝트를 진행하고 가기로 했다.
🦀 Ferris | "먼저 임의의 정수 벡터에 대해서 평균값, 중간값, 최빈값을 구하는 문제야."
🐧 Peter | "벡터 참조를 인자로 받아 정수값을 반환하는 함수를 각각 구현하면 되려나?"
🦀 Ferris | "맞아, 그걸 구현하면 내가 정수 벡터를 준비할게!"
🐧 Peter | "... 어...그래...... 고맙다...ㅋ"
peter@hp-laptop:~/rust-practice/chapter08$ mkdir practice
peter@hp-laptop:~/rust-practice/chapter08$ cd practice/
peter@hp-laptop:~/rust-practice/chapter08/practice$ cargo new integer_vector
Created binary (application) `integer_vector` package
peter@hp-laptop:~/rust-practice/chapter08/practice$ cd integer_vector/
peter@hp-laptop:~/rust-practice/chapter08/practice/integer_vector$ vi src/main.rs
src/main.rs
use std::collections::HashMap; fn main() { let integers = vec![20, 17, 114, 24, 14, 170, 141, 67, 20, 4, 78, 404, 19, 67, 221, 67, 20]; println!("mean: {}", match mean(&integers) { Some(result) => result.to_string(), None => "No Data".to_string(), }); println!("median: {}", match median(&integers) { Some(result) => result.to_string(), None => "No Data".to_string(), }); let m = mode(&integers); println!("mode:{}", { if m.len() == 0 { " No Data".to_string() } else { let mut temp = String::new(); for i in m { temp = format!("{} {}", temp, i.to_string()); } temp } }); } fn mean(ints: &Vec<i32>) -> Option<f64> { if ints.len() == 0 { return None; } let mut result = 0; for i in ints { result += i; } Some(result as f64 / ints.len() as f64) } fn median(ints: &Vec<i32>) -> Option<i32> { if ints.len() == 0 { return None; } let mut sorted = ints.clone(); sorted.sort(); Some(sorted[ints.len()/2]) } fn mode(ints: &Vec<i32>) -> Vec<i32> { if ints.len() == 0 { return vec![]; } let mut result: Vec<i32> = Vec::new(); let mut frequencies = HashMap::new(); let mut max = 0; for i in ints { let count = frequencies.entry(i).or_insert(0); *count += 1; } for (_int, frequency) in &frequencies { if *frequency > max { max = *frequency; } } for (int, frequency) in &frequencies { if *frequency == max { result.push(**int); } } result }
peter@hp-laptop:~/rust-practice/chapter08/practice/integer_vector$ cargo run
Compiling integer_vector v0.1.0 (/home/peter/rust-practice/chapter08/practice/integer_vector)
Finished dev [unoptimized + debuginfo] target(s) in 0.47s
Running `target/debug/integer_vector`
mean: 86.29411764705883
median: 67
mode: 67 20
peter@hp-laptop:~/rust-practice/chapter08/practice/integer_vector$
🦀 Ferris | "비어 있는 벡터까지 고려했잖아?"
🐧 Peter | "너라면 분명 그런 벡터를 줄지도 모른다고 생각해버렸어. 최빈값은 여러 개가 있을 수 있다는 것도."
🦀 Ferris | "개선의 여지가 없다고 확신해?"
🐧 Peter | "그럴라가ㅋ 하지만 일단 현재의 내 실력으론... 여기까지."
🦀 Ferris | "자, 다음은 피그 라틴이야. 여러 가지 바리에이션이 존재하지만 언급된 조건만 고려하도록 하자."
🐧 Peter | "우선 첫 글자가 모음인지 자음인지 구분하고, 이에 따라 변형을 가해야겠군?"
🦀 Ferris | "그렇지! Rust의 문자열은 인덱스를 사용할 수 없으며 UTF-8 형식으로 인코딩되어 저장된다는 걸 기억하라고."
peter@hp-laptop:~/rust-practice/chapter08/practice/integer_vector$ cd ..peter@hp-laptop:~/rust-practice/chapter08/practice$ cargo new pig_latin
Created binary (application) `pig_latin` package
peter@hp-laptop:~/rust-practice/chapter08/practice$ cd pig_latin/
peter@hp-laptop:~/rust-practice/chapter08/practice/pig_latin$ vi src/main.rs
src/main.rs
use unicode_segmentation::UnicodeSegmentation; fn main() { println!("first: {}", pig_latin(String::from("first"))); println!("apple: {}", pig_latin(String::from("apple"))); } fn pig_latin(origin: String) -> String { if origin.len() == 0 { return origin; } let origin = UnicodeSegmentation::graphemes(&origin[..], true) .collect::<Vec<&str>>(); let mut temp = ""; let mut result = String::new(); for (i, ch) in origin.iter().enumerate() { if i == 0 { temp = ch; } else { result = result + ch; } } if temp == "a" || temp == "e" || temp == "i" || temp == "o" || temp == "u" { result = format!("{}{}-hay", temp, result); } else { result = format!("{}-{}ay", result, temp); } result }
peter@hp-laptop:~/rust-practice/chapter08/practice/pig_latin$ cargo run
Compiling pig_latin v0.1.0 (/home/peter/rust-practice/chapter08/practice/pig_latin)
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/pig_latin`
first: irst-fay
apple: apple-hay
peter@hp-laptop:~/rust-practice/chapter08/practice/pig_latin$
🦀 Ferris | "외부 크레이트를 의존성 목록에 추가했구나?"
🐧 Peter | "그렇지ㅋ
Cargo.toml
에unicode-segmentation = "1.6.0"
를 추가함으로써 문자열을 문자 단위로 쉽게 분할할 수 있겠더라고."
🐧 Peter | "다음은... 회사의 부서에 사원을 추가하는 작업?"
🦀 Ferris | "그리고 부서별 사원 리스트, 회사 전체 사원 리스트를 사전순으로 출력할 수 있어야 하지."
🐧 Peter | "일단
Add {employee} to {department}
구조로 입력된다는 걸 가지고 사원과 부서를 뽑아내야겠군... 잘못된 Query가 없다고 기대할게."
peter@hp-laptop:~/rust-practice/chapter08/practice/pig_latin$ cd ..
peter@hp-laptop:~/rust-practice/chapter08/practice$ cargo new company
Created binary (application) `company` package
peter@hp-laptop:~/rust-practice/chapter08/practice$ cd company/
peter@hp-laptop:~/rust-practice/chapter08/practice/company$ vi src/main.rs
src/main.rs
use std::io; use std::collections::HashMap; fn main() { let mut company: HashMap<String, Vec<String>> = HashMap::new(); println!("**************************************************************************"); println!("* Type \"Add {{employee}} to {{department}}\" to insert *"); println!("* Type \"{{department}}\" to retrieve a list of all people in the department *"); println!("* Type \"Company\" to retrieve a list of all people in the company *"); println!("* Type \"Exit\" to exit this program *"); println!("**************************************************************************"); loop { let mut query = String::new(); let mut flag = false; println!("Type the query:"); match io::stdin().read_line(&mut query) { Ok(_) => { if &query == "Exit\n" { break; } else if &query == "Company\n" { view_company(&company); continue; } else { for (dept, _) in &company { if &query == dept { view_department(&company, &query); flag = true; break; } } if flag == false { add_employee(&mut company, &query); } continue; } }, Err(_) => { println!("Cannot read the line. Try again."); continue; } } } println!("Terminated..."); } fn add_employee(company: &mut HashMap<String, Vec<String>>, query: &String) { let mut space = 0; let mut temp = 0; let mut employee = ""; for (i, &item) in query.as_bytes().iter().enumerate() { if item == b' ' { space += 1; if space % 2 == 1 { temp = i+1; } else if space == 2 { employee = &query[temp..i+1]; } } } let department = &query[temp..]; if space == 0 { println!("Try again..."); return; } insert_employee(company, employee, department); } fn insert_employee(company: &mut HashMap<String, Vec<String>>, employee: &str, department: &str) { let key = String::from(department); let value = String::from(employee); let data = company.entry(key) .or_insert({ let temp = Vec::new(); temp }); data.push(value); data.sort(); } fn view_department(company: &HashMap<String, Vec<String>>, department: &String) { let employees = company.get(department); match employees { Some(list) => { for item in list { println!("{}", item); } }, None => (), } } fn view_company(company: &HashMap<String, Vec<String>>) { let mut total: Vec<String> = Vec::new(); for (_dept, list) in company { let mut temp = list.clone(); total.append(&mut temp); } total.sort(); for item in total { println!("{}", item); } }
peter@hp-laptop:~/rust-practice/chapter08/practice/company$ cargo run
Compiling company v0.1.0 (/home/peter/rust-practice/chapter08/practice/company)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/company`
**************************************************************************
* Type "Add {employee} to {department}" to insert *
* Type "{department}" to retrieve a list of all people in the department *
* Type "Company" to retrieve a list of all people in the company *
* Type "Exit" to exit this program *
**************************************************************************
Type the query:
Add Amir to Sales
Type the query:
Add Sally to Engineering
Type the query:
Company
Amir
Sally
Type the query:
Sales
Amir
Type the query:
Engineering
Sally
Type the query:
DepartmentThatNotExists
Try again...
Type the query:
Exit
Terminated...
peter@hp-laptop:~/rust-practice/chapter08/practice/company$
🐧 Peter | "사용 방법은 다 적어놨으니 따로 설명하지 않을게."
🦀 Ferris | "좋아, 그럼 이 쯤 하고 다음 장으로 넘어가자."