본문 바로가기

Programming/Rust로 Euler 문제 풀이

022. Names Scores (이름 문자열에 대해 소팅하고, 점수 구하기)

반응형

​문제 (English)

Using names.txt, a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

For example, when the list is sorted into alphabetical order, COLIN, which is worth 3+15+12+9+14=53, is the 938th name in the list. So, COLIN would obtain a score of $938 \times 53 = 49714$.

What is the total of all the name scores in the file?.

다운로드


Answer: 871198282

문제 분석


이름들 리스트를 정렬해서 순위를 매기고, 그 순위와 해당 이름의 점수(알파벳당 포인트를 매기고 계산)의 곱을 구하라는 문제.

 

소팅을 어떻게 하고, 해당 이름에 대해 알파벳별로 어떻게 점수를 메길지만 알면, 어렵지 않은 문제이다.

 

풀이 1 


다음과 같은 수순.

1)파일에서 이름들을 읽어서 벡터로 저장

2)소팅

3)해당 이름들에 대해서 점수 계산

 

위 수순을 코드로 하면, 

#[test]
fn test(){
    assert_eq!(871198282, answer());
}
#[cfg(test)]
fn answer() -> usize{
    //1. read file
    let names = read_wordfile("input/p22_input.txt");
    let mut names= names.iter().filter(|word| !word.is_empty()).collect::<Vec<_>>();

    //2. sort
    names.sort();

    //3. calculate score
    return names.into_iter().enumerate()
        .map(|(i,s)| get_score(i+1, s)).sum();
}

fn get_score(n:usize, s:&str) -> usize{
    return n * s.bytes().map(|c| (c-b'A'+1) as usize).sum::<usize>();
}

#[cfg(test)]
fn read_wordfile(filename:&str) -> Vec<String>{
    use std::io::{BufRead, BufReader};    
    use std::fs::File;

    let f:File = File::open(filename).expect("file open error");

    let mut v:Vec<String> = Vec::new();
    for bytes in BufReader::new(f).split(b','){
        let mut bytes = bytes.expect("error");
        if bytes.last() == Some(&b','){
            bytes.pop();
        }
        v.push(String::from_utf8(bytes).unwrap().trim_matches('\"').to_string());
    }

    return v;
}

 

파일에 있는 이름들을 split 하는 read_wordfile 코드만이 좀 복잡하다.

 

파일을 BufReader로 읽어내고, 콤마(,)를 기준으로 split 한다. 그리고, 가장 마지막에 콤마가 벡터에 들어갈 수 있는데 그것은 없애고, 또한 이름들을 감싸고 있는 코테이션(")도 없앴다.

 

또한 점수를 계산할 때, 벡터에 들어 있는 해당 이름의 순서를 알아내야 하는 부분이 있는데, 이는 아래와 같이 enumerator를 이용해서 구했다.

names.into_iter().enumerate()
        .map(|(i,s)| get_score(i+1, s)).sum();

 

풀이 2 


hackerrank의 문제는 약간 다르다.

이름들 리스트를 주는 것은 똑같고, 다만 리스트에서 한 이름을 주면, 그 이름에 대한 점수를 계산하는 형태다.

 

이것도 풀이 1과 풀이 루틴은 동일하다.

벡터에 이름들을 담고, 소팅하고, 이름이 주어지면 해당 이름의 점수를 계산한다.

 

여기서는, hackerrank에서 stdin으로부터 입력들을 읽을 때 BufRead를 통해 it.next() 함수로 입력값들을 읽는데, 이 부분을 로컬에서 테스트할 때 문제 사이트에서와 같이 stdin이 아닌, 로컬에서는 파일을 BufRead로 읽어서, 문제사이트와 동일한 코드로 테스트를 진행할 수 있게 하였다. 그 부분에 유의

 

즉, hacker 사이트 코드는 아래와 같고,

let stdin = io::stdin();
let mut it = stdin.lock().lines();

let n = it.next().unwrap().unwrap().trim().parse::<usize>().unwrap();

 

로컬에서 파일을 통해 BufRead인 it를 생성해서 사용하는 것은 아래와 같다.

let file = File::open("input/p22_input1.txt").expect("file open error");
let reader = BufReader::new(file);
let mut it = reader.lines();

let n = it.next().unwrap().unwrap().trim().parse::<usize>().unwrap();

 

해커 사이트에 올린 코드는 아래와 같다. 로컬에서 테스트할 수 있는 코드는 아래편 전체 코드에서 확인.

use std::io::{self, BufRead};

fn main(){
    let stdin = io::stdin();
    let mut it = stdin.lock().lines();
    
    let n = it.next().unwrap().unwrap().trim().parse::<usize>().unwrap();
    let mut names:Vec<String> = Vec::new();
    for _ in 0..n{
        let s = it.next().unwrap().unwrap().trim().to_string();
        names.push(s);
    }
    names.sort();

    let q = it.next().unwrap().unwrap().trim().parse::<usize>().unwrap();
    for _ in 0..q{
        let name = it.next().unwrap().unwrap().trim().to_string();
        println!("{}", get_score_with_name(&names, name));
    }
}

fn get_score_with_name(names:&Vec<String>, name:String) -> usize{
    let pos = names.iter().position(|s| *s==name).unwrap();
    return (pos+1) * name.bytes().map(|c| (c-b'A'+1) as usize).sum::<usize>();
}

 

 

총평


원래의 문제 의도는 소팅(sorting)을 해보라는 것. 그리고, 알파벳 문자로부터 어떻게 점수를 뽑아내는지를 물어보는 문제이다. 

그러나, 소팅은 이미 어떤 프로그래밍 언어에서도 기본 라이브러리로 제공하는 수준이라서, 여기서는 별도로 소팅을 구현하지 않았다. 아마, 다시 소팅을 구현해야만 하는 문제가 있을 것이다. 그때 소팅을 구현해 보겠다.

 

전체 소스코드


p22.rs 

#[test]
fn test(){
    assert_eq!(871198282, answer());
}

#[cfg(test)]
fn answer() -> usize{
    //1. read file
    let names = read_wordfile("input/p22_input.txt");
    let mut names= names.iter().filter(|word| !word.is_empty()).collect::<Vec<_>>();

    //2. sort
    names.sort();

    //3. calculate score
    return names.into_iter().enumerate()
        .map(|(i,s)| get_score(i+1, s)).sum();
}

fn get_score(n:usize, s:&str) -> usize{
    return n * s.bytes().map(|c| (c-b'A'+1) as usize).sum::<usize>();
}

#[cfg(test)]
fn read_wordfile(filename:&str) -> Vec<String>{
    use std::io::{BufRead, BufReader};    
    use std::fs::File;

    let f:File = File::open(filename).expect("file open error");

    let mut v:Vec<String> = Vec::new();
    for bytes in BufReader::new(f).split(b','){
        let mut bytes = bytes.expect("error");
        if bytes.last() == Some(&b','){
            bytes.pop();
        }
        v.push(String::from_utf8(bytes).unwrap().trim_matches('\"').to_string());
    }

    return v;
}

//------------------------------------------
// read names with string
#[test]
fn test1(){
    use std::fs::File;
    use std::io::{BufReader, BufRead};

    let file = File::open("input/p22_input1.txt").expect("file open error");
    let reader = BufReader::new(file);
    let mut it = reader.lines();
    //----------

    let n = it.next().unwrap().unwrap().trim().parse::<usize>().unwrap();
    let mut names:Vec<String> = Vec::new();
    for _ in 0..n{
        let s = it.next().unwrap().unwrap().trim().to_string();
        names.push(s);
    }
    names.sort();

    let q = it.next().unwrap().unwrap().trim().parse::<usize>().unwrap();
    for _ in 0..q{
        let name = it.next().unwrap().unwrap().trim().to_string();
        println!("{}", get_score_with_name(&names, name));
    }
}

#[cfg(test)]
fn get_score_with_name(names:&Vec<String>, name:String) -> usize{
    let pos = names.iter().position(|s| *s==name).unwrap();
    return (pos+1) * name.bytes().map(|c| (c-b'A'+1) as usize).sum::<usize>();
}

 

반응형