Home PS) 오픈채팅방
Post
Cancel

PS) 오픈채팅방

출처
: Programmers

문제

(생략)

채팅방에 들어오고 나가거나, 닉네임을 변경한 기록이 담긴 문자열 배열 record가 매개변수로 주어질 때, 모든 기록이 처리된 후, 최종적으로 방을 개설한 사람이 보게 되는 메시지를 문자열 배열 형태로 return 하도록 solution 함수를 완성하라.

제한사항

  • record는 다음과 같은 문자열이 담긴 배열이며, 길이는 1 이상 100,000 이하이다.
  • 다음은 record에 담긴 문자열에 대한 설명이다.
    • 모든 유저는 [유저 아이디]로 구분한다.
    • [유저 아이디] 사용자가 [닉네임]으로 채팅방에 입장 - “Enter [유저 아이디] [닉네임]” (ex. “Enter uid1234 Muzi”)
    • [유저 아이디] 사용자가 채팅방에서 퇴장 - “Leave [유저 아이디]” (ex. “Leave uid1234”)
    • [유저 아이디] 사용자가 닉네임을 [닉네임]으로 변경 - “Change [유저 아이디] [닉네임]” (ex. “Change uid1234 Muzi”)
    • 첫 단어는 Enter, Leave, Change 중 하나이다.
    • 각 단어는 공백으로 구분되어 있으며, 알파벳 대문자, 소문자, 숫자로만 이루어져있다.
    • 유저 아이디와 닉네임은 알파벳 대문자, 소문자를 구별한다.
    • 유저 아이디와 닉네임의 길이는 1 이상 10 이하이다.
    • 채팅방에서 나간 유저가 닉네임을 변경하는 등 잘못 된 입력은 주어지지 않는다.
(생략)

나의 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def solution(record):
    split_list = []

    for i in record:
        split_list.append(i.split(' '))

    size = len(split_list)

    user_list = []
    # 유저 최초 들어올때 기록됨
    # (join_cnt, user_name)
    user_idx = {}
    # 유저가 최초로 들어올때마다 (+1)
    join_cnt = 0

    # 유저 status 발생 때마다 모두 기록
    # (user_id, user_status)
    # (user_id로 join해야됨)
    log = []
    log_cnt = 0
    for i in range(size):
        parsing = split_list[i]
        status_parsed = parsing[0]
        if (status_parsed == "Enter"):
            tmp_id = parsing[1]
            tmp_name = parsing[2]
            try:
                refer_user_join = user_idx[tmp_id][0]
            except:
                refer_user_join = False

            if (refer_user_join is False):
                user_list.append(User(tmp_id, tmp_name, status_parsed))
                user_idx[tmp_id] = (join_cnt, tmp_name)
                join_cnt += 1
                refer_user_join = user_idx[tmp_id][0]
            else:
                user_list[refer_user_join].user_name = tmp_name
            user_list[refer_user_join].status_list.append(status_parsed)
        elif (status_parsed == "Leave"):
            tmp_id = parsing[1]
            refer_user_join = user_idx[tmp_id][0]
            user_list[refer_user_join].status = status_parsed
            user_list[refer_user_join].status_list.append(status_parsed)
        else:
            tmp_id = parsing[1]
            changed_name = parsing[2]
            refer_user_join = user_idx[tmp_id][0]
            user_list[refer_user_join].user_name = changed_name
        # 로그 기록
        log.append((parsing[1], status_parsed))

    result = []
    for uid, stts in log:
        result.append(define_message(user_list[user_idx[uid][0]].user_name,
                       stts))
    
    answer = list(filter(None, result))
    
    return answer

class User:
    def __init__(self, user_id, user_name, status):
        self.user_id = user_id
        self.user_name = user_name
        self.status = status
        self.status_list = []

def define_message(user_name, status):
    output_msg = ""
    if status == "Enter":
        output_msg = user_name + "님이 들어왔습니다."
    elif status == "Leave":
        output_msg = user_name + "님이 나갔습니다."
    return output_msg

이번 문제는 뭔가
깔끔하게 풀 수 있을 것 같았는데
출력되는 이름은 최종 변경된 이름이고,
출력 순서는 발생 순서여야 한다는 조건이
조금 까다롭게 느껴졌다.

클래스를 만들어서 생성자까지 이용하여 활용하려 했으나
생성자로 입장, 퇴장 메시지를 내는 부분에서
매끄럽게 되지가 않아 별도 함수로 바꿨다.



다른 사람들의 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def solution(record):
    answer = []
    namespace = {}
    printer = {'Enter':'님이 들어왔습니다.', 'Leave':'님이 나갔습니다.'}
    for r in record:
        rr = r.split(' ')
        if rr[0] in ['Enter', 'Change']:
            namespace[rr[1]] = rr[2]

    for r in record:
        if r.split(' ')[0] != 'Change':
            answer.append(namespace[r.split(' ')[1]] + printer[r.split(' ')[0]])

    return answer

(출처: 프로그래머스 스쿨 다른사람 풀이)

조건문에서 in을 활용한 것이 신기했다.
흔히 알려진 연산자이면서도
막상 이렇게 활용되는 게 약간 생각지못했다.

또, 특히
출력 구문을 해당 영단어와 매칭시켜
딕셔너리로 저장하고 시작한 게 인상적이다.


1
2
3
4
5
6
7
8
9
10
11
def solution(record):
    user_id = {EC.split()[1]:EC.split()[-1] 
                for EC in record 
                if EC.startswith('Enter') or EC.startswith('Change')
            }
    return [f'{user_id[E_L.split()[1]]}님이 들어왔습니다.' 
        if E_L.startswith('Enter') 
        else f'{user_id[E_L.split()[1]]}님이 나갔습니다.' 
    for E_L in record if not E_L.startswith('Change')
    ]

(출처: 프로그래머스 스쿨 다른사람 풀이)
이건 편의상 코드를 개행했다.
(원래는 딱 두 줄이었다.)

각각 하나의 딕셔너리와 리스트를 이용하여
구분, 결과 출력을 해낸 게 인상적이다.

Contents