📍 신고 결과 받기
k
번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.이용자의 ID가 담긴 문자열 배열 id_list
, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report
, 정지 기준이 되는 신고 횟수 k
가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.
id_list
의 길이 ≤ 1,000id_list
의 원소 길이 ≤ 10id_list
의 원소는 이용자의 id를 나타내는 문자열이며 알파벳 소문자로만 이루어져 있습니다.id_list
에는 같은 아이디가 중복해서 들어있지 않습니다.report
의 길이 ≤ 200,000report
의 원소 길이 ≤ 21report
의 원소는 "이용자id 신고한id"형태의 문자열입니다.k
≤ 200, k는 자연수입니다.id_list
에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.report
는 중복이 가능하다. 그러므로 중복을 허용하지 않는 Set으로 다루자!{신고 당한 유저: [신고 한 유저들]}
형태의 Map으로 다뤄 쉽게 처리하자.k
와 같거나 커야 하니 filter를 사용해 정지 당하지 않은 유저는 제외하자.{유저 ID: 메일을 받을 횟수}
형태로 Map을 만들어 답을 다루자.{신고 당한 유저: [신고 한 유저들]}
형태의 Map을 돌면서 메일을 받을 횟수를 1씩 늘려준다.class Solution {
fun solution(id_list: Array<String>, report: Array<String>, k: Int): IntArray {
var realReport = report.toSet().map { it.split(" ") }.groupBy({ it.last() }, { it.first() }).filter { it.value.size >= k }
var idList = id_list.associate { it to 0 }.toMutableMap()
realReport.map {
it.value.map { userId ->
idList[userId] = idList[userId]!! + 1
}
}
return idList.values.toIntArray()
}
}
응용이 서툴렀던 groupBy도 써보고, associate도 써봐서 근래 풀었던 문제 중 가장 마음에 드는 풀이였다. 즉, 나 치고는 잘 풀었다! 매일 다른 사람 풀이를 염탐한 효과가 드디어 나타났다. 사실 문제가 이전 것들 보다는 좀 쉬웠던 이유도 있긴 하다.
나도 되고 싶다. 한 줄 변태. 짧게 쓴다고 다 좋은 풀이가 아니겠지만, 짧게 쓰는 걸 알면서 가독성 좋게 풀어 쓰는 것과 짧게 못 써서 길게 풀어 쓰는 것의 차이는 클 것이다. 게다가 짧게 쓰는데 성능까지 좋다? 그냥 뇌에 박아놓고 여기저기 써봐야한다.
그런 의미에서, Sequence를 아는가. Java의 Stream과 유사하다는데 내가 Java를 잘 모르니 일단 패스하고 Kotlin으로 설명하겠다. 가장 큰 차이점은 다음과 같다.
이렇게만 보면 이해가 안될 것이다. (나는 그렇다.) 그래서 예제로 알아보면!
collection.map { ... }
.filter { ... }
.map { ... }
.groupBy { ... }
자 위의 코드를 실행하면 map을 수행한 컬렉션 하나, filter를 수행한 컬렉션 하나, 다시 map을 수행한 컬렉션 하나, groupBy를 수행한 컬렉션 하나.. 연산 중에 총 4개의 컬렉션이 나오게 된다! 그러나 Sequence를 사용하게 되면, 마지막 groupBy에서 한 번에 연산을 수행해서 최종 결과만을 반환하게 된다! 추가로 원하는 값을 이미 찾은 경우 전체 원소를 순회하지 않을 수도 있어서 Collection 보다 향상된 전체 처리 능력을 갖고 있다고 한다.
그렇지만 길이가 짧거나 동작이 간단한 경우에는 오히려 해가될 수 있으니, 잘 판단해서 사용해야 한다고 한다.
돌아와서, 오늘 가져온 다른 사람의 풀이는 한 줄 변태에 이 Sequence를 사용했다. 그리고 나와 달랐던 점은, getOrDefault
를 사용해 메일을 받지 않는 사람은 0을 반환하게끔 처리했다.
class Solution {
fun solution(id_list: Array<String>, report: Array<String>, k: Int): IntArray =
// [ [신고한 사람, 신고 받은 사람], ... ] 형태의 Collection
report.map { it.split(" ") }
// {신고 받은 사람: [[신고한 사람, 신고 받은 사람], ... ]} 형태의 Map
.groupBy { it[1] }
// 여기서 부터 run 연산까지 처리는 마지막 줄에서 한꺼번에 처리
.asSequence()
// 같은 사람을 여러 번 신고한 경우 제외, value만 다룬다.
.map { it.value.distinct() }
// 신고 받은 사람 중, 정지를 당한 사람만 추출
.filter { it.size >= k }
// [ [ [신고한 사람, 신고 받은 사람], ... ] ] 형태를
// [ [신고한 사람, 신고 받은 사람], ... ] 형태로 변환
.flatten()
// 신고한 사람만 추출
.map { it[0] }
// 신고한 사람을 Key로 하는 Map
// 여기서 남아있는 신고한 사람들은, 메일을 받게 될 사용자를 의미
.groupingBy { it }
// 신고한 사람의 수(메일을 받게 될 수)를 구한다.
.eachCount()
// id_list를 돌며, 해당하는 사람의 수가 존재한다면 그 수로 처리하고,
// 아니라면 0으로 처리한다.
.run { id_list.map { getOrDefault(it, 0) }.toIntArray() }
}
Sequence 라는 것을 알게되어서 좋았던 문제였다. 물론 문제에서 알려준 것은 아니다.. 다음에 계산이 복잡하고 처리할 데이터가 많다면 사용해봐야겠다.