리트코드 937번 문제(로그 파일 재정렬)이다.
URL : https://leetcode.com/problems/reorder-data-in-log-files/
#937 Reorder Data in Log Files
로그를 재정렬하라. 기준은 다음과 같다.
1. 로그의 가장 앞 부분은 식별자이다.
2. 문자로 구성된 로그가 숫자 로그보다 앞에 온다.
3. 식별자는 순서에 영향을 끼치지 않지만, 문자가 동일한 경우 식별자 순으로 한다.
4. 숫자 로그는 입력 순서대로 한다.
5. 문자 로그는 사전 순으로 정렬한다.• Input :
logs = ["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero"]
• Output :
["let1 art can","let3 art zero","let2 own kit dig","dig1 8 1 5 1","dig2 3 6"]
먼저 문제 상세하게 이해해보자. 입력 예제에서 logs
라는 배열 안에 문자열 값들이 있는데, 그 문자열 값에서 공백을 첫번째 단어들은 모두 '식별자'로 순서에 영향을 끼치지는 않지만 로그 내의 문자가 동일한 경우에는 식별자로 순서를 정한다. 기본적으로 문자 로그는 사전 순으로, 숫자 로그는 입력 순으로 정렬하고 문자 로그는 숫자 로그보다 앞에 와야한다.
식별자를 제외한 나머지의 값들이 문자인지 숫자인지 판단하고 구분하는 것이 먼저이다. 먼저 split
을 이용하여 문자열을 공백을 기준으로 자른 단어들의 리스트로 만든 후, isdigit()
을 이용하여 로그 값이 문자인지 숫자인지 판별해야한다.
letters, digits = [], []
if log.split()[1].isdigit():
digits.append(log)
else:
letters.append(log)
문자와 숫자 판별 후 각 로그 값을 맞는 리스트에 저장해 둔다. 숫자 로그는 입력 순서를 유지하면 되므로 더이상 건들이지 않고 문자 로그를 모아놓은 리스트를 다음과 같이 람다 함수와 sort/key를 이용하여 사전 순으로 정렬한다.
letters.sort(key = lambda x: (x.split()[1:], x.split()[0]))
마지막으로 문자 로그들이 숫자 로그들보다 먼저 나와야하므로 letters + digits
를 리턴한다.
이 문제의 풀이를 다음과 같은 코드로 정리할 수 있다.
from typing import *
class Solution:
def reorderLogFiles(self, logs: List[str]) -> List[str]:
letters, digits = [], []
for log in logs:
if log.split()[1].isdigit():
digits.append(log)
else:
letters.append(log)
letters.sort(key = lambda x: (x.split()[1:], x.split()[0]))
return letters + digits
split()
함수는 문자열을 공백이나 특정 문자를 기준으로 분리하여 분리된 값을 요소로 하는 리스트를 리턴하는 함수이다. 원형과 사용법은 다음과 같다.
<list>.split(sep = <char>, maxsplit = <int>)
>>> array1 = 'abc de fg hijk l mno pq rstuv w xyz'
>>> array2 = 'a:b:cd:e:fgh'
>>> array1.split() # 공백을 기준으로 문자열을 쪼개어 리스트에 저장
['abc', 'de', 'fg', 'hijk', 'l', 'mno', 'pq', 'rstuv', 'w', 'xyz']
>>> array2.split(':') # 문자 ':'을 기준으로 문자열을 쪼개어 리스트에 저장
['a', 'b', 'cd', 'e', 'fgh']
>>> array2.split(sep=':') # array2.split(':')와 같음
['a', 'b', 'cd', 'e', 'fgh']
>>> array2.split(':', 3) # 문자 ':'을 기준으로 문자열을 쪼개되 최대 3번 분할하여 리스트에 저장
['a', 'b', 'cd', 'e:fgh']
>>> array2.split(sep=":", maxsplit=3) # array2.split(':', 3)와 같음
['a', 'b', 'cd', 'e:fgh']
>>> array1.split(maxsplit=4) # sep 파라미터가 없을 시에는 공백을 기준으로 쪼개되 maxsplit만큼 분할하여 저장
['abc', 'de', 'fg', 'hijk', 'l mno pq rstuv w xyz']
isdigit()
함수는 해당 문자열이 숫자로만 이루어져 있으면 True를 리턴하는 함수이다. 숫자로만 이루어져 있어야하기 때문에 음수를 나타내기 위해 '-'(마이너스) 기호를 붙이거나 소수를 나타내기 위해 '.'을 쓴다면 False를 리턴한다. 문자열에 오로지 숫자만 있어야 True를 반환한다. 원형과 사용법은 다음과 같다.
<list>.isdigit()
>>> a = '123'
>>> b = '-123'
>>> c = '1.23'
>>> d = '1이삼'
>>> e = '일이삼'
>>> a.isdigit()
True
>>> b.isdigit()
False
>>> c.isdigit()
False
>>> d.isdigit()
False
>>> e.isdigit()
False
먼저 sort()
는 리스트를 정렬하는데 (정렬된 리스트를 반환하고 그 리스트 자체는 변경하지 않는 sorted()
함수와 반대로) 해당 리스트 자체를 변경한다. 여기서 정렬의 디폴트값은 오름차순 정렬이다. 파라미터로는 key
와 reverse
가 있다. 원형은 다음과 같다.
<list>.sort(key = <function>, reverse = <bool>)
key
에 대한 값으로는 함수가 들어올 수 있는데, 람다식으로 사용이 가능하다. 다음 코드를 보자.
>>> arr = [[20, 'banana'], [5, 'chocolate'], [100, 'apple']]
>>> arr.sort(key = lambda x: x[0]) # 첫 번째 요소인 정수 값을 기준으로 오름차순 정렬
[[5, 'chocolate'], [20, 'banana'], [100, 'apple']]
>>> arr.sort(key = lambda x: x[1]) # 두 번째 요소인 문자열 값을 기준으로 오름차순(사전순) 정렬
[[100, 'apple'], [20, 'banana'], [5, 'chocolate']]
다음과 같이 key
값에 따라 정렬하는 기준이 달라진다. 또 다음과 같이 정렬 기준의 우선순위를 정할 수 있다.
>>> arr = [[2, 'banana', 'zebra'], [5, 'chocolate', 'yellow'], [1, 'appple' 'save'],
[2, 'photo', 'alpha'], [5, 'dynamic', 'post']]
>>> arr.sort(key = lambda x: (x[0], -x[2])
[[1, 'appple', 'save'], [2, 'banana', 'zebra'], [2, 'photo', 'alpha'], [5, 'chocolate', 'yellow'], [5, 'dynamic', 'post']]
위의 코드는 key
의 값으로 lambda x: (x[0], -x[2])
를 넣었다. 이는 고려할 사항이 여러가지일 때, 우선순위를 정하는 방법인데 ()
안에 튜플의 형태로 기준을 차례대로 넣어주면 된다. 또 -
를 붙였을 때는 오름차순이 아니라 내림차순으로 정렬이 된다. 따라서 위의 코드는 첫 번째 요소를 기준으로 먼저 오름차순 정렬하고 그 값이 같을 시 세번째 요소를 기준으로 내림차순 정렬하라는 코드이다.