240520_TIL

J Lee·2024년 5월 20일
post-thumbnail

아무리 사소하더라도 배움이 없는 날은 없다.

SQL코드카타 124번
SQL 함수 중 group_concat을 알아야 제대로 풀 수 있는 함수.
지금까지는 concat함수만 알고 써 봤는데, 이번 문제를 풀어보면서 공부할 수 있었다.
concat이 같은 row에 있는 서로 다른 컬럼들의 값을 합치는 함수라면,
group_concat은 서로 다른 row에 있는 값들을 하나의 문자열로 합치는 함수다.



예를 들어 위의 쿼리처럼

group_concat(product,",") as test

로 써 놓으면 test컬럼 안에 해당 날짜의 상품들이 모두 모이기는 한 것을 확인할 수 있다. 다만,

  1. 문제에서 언급한 대로 컬럼 안의 값들이 오름차순으로 정렬되지 않았고
  2. 상품 뒤에 ,가 2개 붙는 문제가 있으며
  3. 6월 2일의 경우 중복된 항목 Mask가 모두 출력되기도 하고
  4. 상품이 모두 끝난 후에도 ,가 출력되는 문제가 있으므로

이 부분은 튜닝이 되어야 한다.

SELECT sell_date,
       Count(DISTINCT product) AS num_sold,
       Group_concat(DISTINCT product ORDER BY product SEPARATOR ',') AS products
FROM   activities
GROUP  BY 1
ORDER  BY 1
  1. 오름차순 정렬을 위해 product 뒤에 order by를 써 주었고
  2. 상품 뒤에 ,가 2개 붙는 문제를 해결하기 위해 (product,",")가 아니라 끝부분에 separator ','로 처리해 주었다. 이렇게 하면 자동으로 product끼리만 ,로 연결해 주고, 끝부분에 ,가 또 반복되는 문제가 생기지 않는다.
  3. 중복을 제거하기 위해 group_concat 안에 distinct로 명시해 주었다.
  4. 2번과 함께 해결됨

사실 separator ','부분을 쓰지 않고 order by product로만 마무리해 줘도 알아서 ,로 구분은 된다. ,가 아니라 다른 문자를 통해 연결해줘야 할 상황에서만 separator를 지정해 주어도 될 듯.


알고리즘 코드카타 46번
오늘도 미쳐버린 알고리즘.

네오와 프로도가 숫자놀이를 하고 있습니다. 네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다.
다음은 숫자의 일부 자릿수를 영단어로 바꾸는 예시입니다.

1478 → "one4seveneight"
234567 → "23four5six7"
10203 → "1zerotwozero3"

이렇게 숫자의 일부 자릿수가 영단어로 바뀌어졌거나, 혹은 바뀌지 않고 그대로인 문자열 s가 매개변수로 주어집니다. s가 의미하는 원래 숫자를 return 하도록 solution 함수를 완성해주세요.

후....
어떻게 풀어야 할지 머리를 짜내고 있는데 오늘은 도저히 생각이 안 난다.

어차피 숫자는 바꾸고 자시고 할 필요가 없으니까 반복문을 안 탄다고 치고,
나머지 문자열들은 반복문에서 어떻게 돌려야 할지가 고민이었다. 평상시에 쓰던 반복문처럼 한 글자씩 반복해서는 당연히 답을 구할 수가 없겠는데, 도저히 안 되겠어서 채찍피티 선생님의 도움을 받아서 해결했다.

def solution(s):
    x = ['zero','one','two','three','four','five','six','seven','eight','nine']
    y = ""
    z = ""
    for i in s:
        if(i.isnumeric()):
            y+=i
        else:
            z+=i
        if z in x:
            y+=str(x.index(z))
            z=""
    return int(y)

우선 'zero'부터 'nine'까지의 문자열을 담은 리스트 x를 선언해 둔다.
이 리스트 x를 굳이 만들어놓는 이유는 각각의 문자열(one, two, ...)들의 index를 따와서 후반부 연산에 활용하기 위함이다. 따라서 zero를 nine 뒤에 쓰거나 하면 안 되고, 무조건 zero부터 nine의 순으로 적어야 한다. 그리고 빈 문자열 y와 z를 각각 선언해 준다.

이제 문제에서 입력받은 문자+숫자의 조합 s의 각 요소를 for 반복문에 넣고 돌린다. 첫 번째 if문은 i가 숫자인지를 묻는(isnumeric) 것으로, 여기서 true값이 나오면 i가 숫자라는 의미이므로 바로 y에 i를 추가한다. (y는 나중에 정답 결과를 담을 문자열이다.)

그리고 i가 숫자가 아니라 문자라면, 문자열 z에 i를 담는다. z는 결과를 출력하기 위함이 아닌, 담겨있는 문자열들을 위에서 선언한 x의 index와 맞춰보기 위해 임시로 만들어 둔 문자열이다. z의 역할은 연산에 쓰이는 것밖에 없다.

s의 구성요소 i에 대해 반복문이 돌아가면서 y와 z에 각각 숫자와 문자열이 채워지고 있을 것인데, 이와 동시에 z와 x에 대해서도 if문이 실행된다. 예를 들어 s = "one4seveneight" 이라면, 3번째 요소까지 반복문이 돌고 나면 z(one)가 x에 포함되게 된다. 따라서 정답을 담을 y에 index(z), 즉 index(one)을 문자열(str) 형태로 바꿔서 담는다. 리스트 x에서 index(one) = 1이므로, 4가 y에 추가되기 전에 이미 y에는 1이 담겨있는 셈이다. 그리고 z는 다시 "", 즉 빈 문자열로 돌아간다. 4가 추가되고 나면 y = 14가 된다.

같은 원리로 seven까지 반복문이 돌면 y에 7이 추가되어 147이 되고, 반복문이 모두 끝나면 y = 1478이 된다. (이 때 y의 타입은 문자형이다.) 문제에서는 s를 '숫자로' 출력하라고 했으므로, return int(y)까지 적어주면 1478이 정수형으로 출력된다.

다른 리스트의 index까지 연산에 활용해야 하기 때문에 어렵게 느껴졌던 문제. 기존에 썼던 for 반복문처럼 한 글자씩 반복하는 것에만 꽂혀있으면 평생 못 풀었을 문제다. 오늘은 컨디션이 너무 떨어져서 복습까지는 어렵겠고 내일 다시 정리하면서 논리를 숙지해 놔야지.

profile
기본기를 소홀히 하지 말자

0개의 댓글