[Swift] [23일차] 오픈채팅방

·2024년 12월 30일
0

SwiftAlgorithm

목록 보기
26/105

programmers-오픈채팅방

문제 설명

  1. 유저들이 들어오고 나간 것의 로그를 찍어주는 것
  2. 중간에 닉네임이 변경되면 result에서도 처음부터 반영되도록하기
  3. 닉네임과 uid를 잘 구분

문제 접근

  1. result에 마지막에 찍히는 거니까 uid로 딕셔너리로 관리해주다가 마지막에 출력만 하면 될 것 같은느낌?
  2. 들어오고 나간거는 이제 함수로 따로 관리해주고

문제풀이

import Foundation

func solution(_ record: [String]) -> [String] {
    var user_data = [String: String]()
    var command_array = [String]()
//    처음돌릴때는 로그안찍고 ㄱ
    func printLog(
        _ type: String,
        _ name: String,
        _ nickname: String,
        _ log: Bool = false
    ) {
        switch type {
        case "Enter":
            user_data[name] = nickname
            if log { command_array.append("\(user_data[name])님이 들어왔습니다.") }
        case "Leave":
            if log { command_array.append("\(user_data[name])님이 나갔습니다.") }
        default:
            if !log {
                user_data[name] = nickname
            }
        }
    }
    for log in record {
        let logArray = log.split(separator: " ")
        let type = logArray[0]
        let name = logArray[1]
        let nickname = logArray.count > 2 ? logArray[2] : ""
        printLog(String(type), String(name), String(nickname))
    }
    for log in record {
        let logArray = log.split(separator: " ")
        let type = logArray[0]
        let name = logArray[1]
        let nickname = logArray.count > 2 ? logArray[2] : ""
        printLog(String(type), String(name), String(nickname), true)
    }
    return command_array
}

print(solution(["Enter uid1234 Muzi", "Enter uid4567 Prodo", "Leave uid1234", "Enter uid1234 Prodo", "Change uid4567 Ryan"]))
  1. 일단 든 생각은 command_array라는 정답배열에 담아주는 것인데, 닉네임이 enter, change를 통해 변경될 수 있으므로, 로그를 안찍은채 한번 쭉돌려주고, 이제 최신화된 친구들로한 번 더 돌려주는 것이었다.
  2. 그런데 이렇게 하니까
["Optional(\"Muzi\")님이 들어왔습니다.", 
"Optional(\"Prodo\")님이 들어왔습니다.", 
"Optional(\"Muzi\")님이 나갔습니다.", 
"Optional(\"Prodo\")님이 들어왔습니다."]

이런식으로 옵셔널로찍혀서 이게 하나의 이쁜 문자열처럼 되지가 않는 것이었다.


case "Enter":
            if !log {
                user_data[name] = nickname
            }
            if log { command_array.append("\(user_data[name]!)님이 들어왔습니다.") }
        case "Leave":
            if log { command_array.append("\(user_data[name]!)님이 나갔습니다.") }

이 부분을 강제 언래핑을 해줬다 어처피 logfalse일때 이미 딕셔너리에 담겨주었기 때문에 문제는 없었다.


채점 결과

정확성: 100.0
합계: 100.0 / 100.0

뭔가 그대로 두번씩 돌려주는게 더 효율적인 방법이 있을 것 같았는데, 일단 구현이 중요한 문제였는지 정답처리를 받을 수 있었다.

코드개선

똑같은 반복문 두개는 너무 원시인 코드 같아서 한 번으로 바꿔주고, 그 과정에서 튜플로 바꿔주었다. command_array에 반영해주면서 uid를 넣어주고, 이제 마지막에 string배열로 만드는 과정에서 map을 통해서 구조분해해주면 된다 !

import Foundation

func solution(_ record: [String]) -> [String] {
    var user_data = [String: String]()
//    튜플로 바꾸기
    var command_array = [(String, String)]()
//    처음돌릴때는 로그안찍고 ㄱ

    for log in record {
        let logArray = log.split(separator: " ")
        let type = String(logArray[0])
        let name = String(logArray[1])
        let nickname = logArray.count > 2 ? String(logArray[2]) : ""

        switch type {
        case "Enter":
            user_data[name] = nickname
            command_array.append((type, name))
        case "Leave":
            command_array.append((type, name))
        case "Change":
            user_data[name] = nickname
        default:
            break
        }
    }
    return command_array.map { command in
        let (type, name) = command
        let nickname = user_data[name]!
        return type == "Enter" ? "\(nickname)님이 들어왔습니다." : "\(nickname)님이 나갔습니다."
    }
}

타인의 코드

import Foundation

func solution(_ record:[String]) -> [String] {
    let actions = ["Enter":"님이 들어왔습니다.", "Leave":"님이 나갔습니다."]
    var a = [String:String]()

    record.forEach {
    let separated = $0.components(separatedBy: " ")
    if separated.count > 2 {
        a[separated[1]] = separated[2]
    }
}

return record.filter { !$0.contains("Change") }.map { (value:String) -> String in
        let separated = value.components(separatedBy: " ")
        let newString = a[separated[1]]! + actions[separated[0]]!
        return newString
}
}

Q : components는 무엇인가 ? split이랑 뭐가 다르지 ??

A : 얘는 반환값이 Array<Substring> 이 아니라 Array<String> 인 것만으로도 사용할만하다고 생각했다. 정리된 표는 다음과 같다.
또한 파라미터를 여러개 해줄 수 있어서, 좀 더 복잡한 구분이 필요할 때는 components를 사용해주는게 좋다! (다만 import Foundation 필수!! )

주요 차이점 비교

특징components(separatedBy:)split(separator:)
구분 기준문자열(String)문자(Character)
반환 타입[String][Substring]
빈 문자열 처리빈 문자열 포함기본적으로 빈 문자열 제거
구현 위치Foundation (NSString 기반)Swift 표준 라이브러리
속도다소 느림더 빠름
구분자 복잡도여러 문자로 나누기 가능단일 문자 기준

다시 코드 설명으로 돌아가면..

  1. separated.count>2 일때.. 즉, Leave가 아닐때로 규정해서 a(user_database)를 최신화 시켜주고,
  2. return해줄때는 Change를 제외하고, 값을 array에 넣어주는 것이다.

코드의 로직은 나랑 엄청 유사했는데 양은 3배 차이가 날 정도로 차이가 좀 났던 것 같다.
이번 문제풀이에서는 맨날 split만 쓰던 내가 components활용을 얻어간다고 생각을 하면 좋을 것 같다.

profile
기억보단 기록을

0개의 댓글