문제
Note: 문제 이름은 임의로 작성한 것 입니다. 아래는 문제의 전체가 아닌 일부 캡쳐입니다.
이어지는 내용:
# your iterator should return the following sequence of integers:
[137, -104, 0, 1, 0, -1]
풀이 및 답
이 문제가 가장 찝찝하게 풀었던 문제이다.
문제에서 왜 class구현을 요구하는 지와 string처리가 메인인 문제에서 왜 굳이 File의 개념을 넣었지가 아직도 이해되지 않는다.
아무튼 문제가 시키는대로 하기위해 껍데기를 만들었다.
class FileIterator(object):
def __init__(self, f):
self.valid_integers = []
for line in f:
pass
def get_iterator(self):
return self.valid_integers
def solution(file_object):
iterator = FileIterator(file_object)
return iterator.get_iterator()
이후, 다시 문제를 읽었다. 역시나 위의 요구사항들은 별 상관이 없다. 그냥 string처리 하는 것이 메인이다. 하나의 라인(\n으로 분리된) 안에서 valid integer의 정의는 아래와 같았다.
- 한 자릿수 이상의 숫자다.
- 단, leading zeros가 없어야 한다.
- 선택적으로, 숫자 앞에 + 또는 - sign이 한번만 붙을 수 있다.(선택적이므로 없어도 된다는 의미)
- 숫자의 범위는 -1,000,000,000 ~ 1,000,000,000 이다.
- 숫자 양옆에 white spaces(나는 margin이라 칭함)는 허용한다.
- 숫자 사이사이에 white spaces는 허용하지 않는다.
- integer이므로 당연히 정수만 허용한다.
위의 조건을 만족해야만 valid integer이고, 나머지는 invalid이다. invalid는 코멘트처리(무시)하고 valid한 값들만
리턴하는 것이 문제이다.
우선, python인터프리터로 그냥 int 형 변환이 얼마나 잘 되는지 문제에서 예제로 들어주는 string들에 대해서 테스트해봤다.
# invalid cases based on problem definition
int('2u1') # raise ValueError Exception
int('23.9') # raise ValueError Exception
int('#12') # raise ValueError Exception
int('00')
int('++1') # raise ValueError Exception
int('2000000000')
int('2 58') # raise ValueError Exception
int('++3') # raise ValueError Exception
int('five') # raise ValueError Exception
# valid cases based on problem definition
int('137')
int('-104')
int('+0')
int('+1')
int('-0')
int('-1')
오… 기본 built-in 함수인 int 형 변환이 거의 다 해준다. 날로먹을 수 있겠다 라는 생각을 잠깐했다.
위의 테스트를 진행하고 나서, regex를 이용해서 white spaces, leading zeros조건을 판단하고나서 int 형 변환을 한 후에 range 조건만 체크하면 될거라 생각했다.
이를 로직으로 구현하기 위해 regex패턴 구현을 아래와 같이 시도했다.
import re
class FileIterator(object):
def __init__(self, f):
self.valid_integers = []
for line in f:
if re.match("(\s*)([+-]?)([0-9]{1,10})(\s*)", line):
try:
integer = int(line)
# range check
if -1000000000 < integer < 1000000000:
self.valid_integers.append(integer)
except:
pass
...
..
.
위의 코드에서 re.match는 하나의 string안에서 패턴이 계속 반복되어도 match object가 리턴되기 때문에 if문이 True처리 된다.
다시 말하면, 위의 regex패턴을 적용하면 “ 12 34 “가 valid integer처리가 된다는 의미이다.
문제를 풀때는 침착하지 못해서 이를 strip() built-in 함수를 사용해서 해결하고 regex패턴을 바꿨는데, 사실 re.fullmatch를 사용하면 해결되는 문제였다.
그리고 이 패턴은 여전히 leading zeros를 처리하지 못했다. leading zeros를 처리하는 regex 패턴은 많은 시간 고민해도 생각나지 않아서,
tricky한 방법을 쓰기로 하여 다음과 같은 코드가 작성됐고, 이를 최종 제출하였다.
class FileIterator(object):
def __init__(self, f):
self.valid_integers = []
for line in f:
line = line.strip()
if re.fullmatch("([+-]?)([0-9]{1,10})", line):
try:
integer = int(line)
# range check
range_check = -1000000000 < integer < 1000000000
# leading zeros check
removed_sign = re.sub("[+-]", "", line)
leading_zeros_check = removed_sign == str(int(removed_sign))
if range_check and leading_zeros_check:
self.valid_integers.append(integer)
except:
pass
...
..
.
이 코드를 위의 문제 정의에 맞춰서 보면,
- 한 자릿수 이상의 숫자다. (regex패턴이 처리)
- 단, leading zeros가 없어야 한다. (leading_zeros_check가 처리)
- 선택적으로, 숫자 앞에 + 또는 - sign이 한번만 붙을 수 있다.(선택적이므로 없어도 된다는 의미) (regex패턴이 처리)
- 숫자의 범위는 -1,000,000,000 ~ 1,000,000,000 이다. (range_check가 처리)
- 숫자 양옆에 white spaces(나는 margin이라 칭함)는 허용한다. (strip 내장함수 처리)
- 숫자 사이사이에 white spaces는 허용하지 않는다. (regex패턴이 처리)
- integer이므로 당연히 정수만 허용한다. (regex패턴, int 내장함수 처리)
와 같이 처리됐다. 찜찜하지만 더 이상 테스트할 케이스가 생각나지 않아 제출하였고, 결과는 다음과 같았다.
task 3의 score를 보니 하나의 테스트 케이스를 통과하지 못한 것 같다. 역시 찜찜하긴 했는데, 어떤 케이스가 통과하지 못한 건지는 여전히 알 수 가 없다.