이벤트 문제를 가지고 예를 들겠습니다.
문제는 "N 명의 리스트에서 랜덤으로 k명을 뽑아서 출력한다." 입니다.
저는 코드가 짧은 것을 좋아해서 파이선에서는 권하지 않는 1줄 코딩을 선호합니다.
왜냐하면 의미상으로 "1~m-1 range 에서 c 개를 sample 해서 sorted"
명확하기 때문입니다. 마치 영어의 복문을 읽는 것과 유사하며,
잘 이해가 되지 않는 다고 하더라도 의미를 알면 파라미터를 유추해 낼 수 있습니다.
from random import sample
(lambda m, c: sorted(sample(range(1,m+1), c)))(45, 6)
저렇게 짜면 날로먹는 것이 아니냐, 랜덤을 이용해서 소중히 정성스럽게 짜야하는것 아니냐?
날로먹는것이 맞는데, 날로먹어야 할 것은 날로 먹는 것이 정답입니다.
DIY (Do not repeat yourself)
제가 랜덤 라이브러리를 잘 몰랐을때 random 을 이용해서 짠 적이 있습니다.
시험때여서 1분이 아까웠지만, 직접 짜느라 5분여를 까먹었습니다.
끝나고 나서 shuffle, sample 과 같은 라이브러리 도구가 있다는 사실을 알고는 허무했습니다.
라이브러리를 써야 하는 이유는 사실 다른 곳에 있습니다. (DRY 로 얻을 수 있는 이익)
내가 만든 로직보다 많은 사람들이 고민해서 이미 만들어 놓은 것입니다.
더 이상 잘 짤 수 없습니다. 물론 테스트도 필요 없습니다. 믿고 쓰면 되지요.
새로운 라이브러리를 사용하는 경우라면 이리 저리 따져봐야합니다만,
shuffle 이나 sample 은 이미 오랜 시간 사용되어져 왔고 검증되었습니다.
지금 python 이나 java 에서 라이브러리 소스를 보십시오.
그럼 라이브러리를 모른다고 했을때, 어떻게 접근해야 하는지 알아 봅니다.
입출력에 따라서 흐름을 먼저 살펴봅니다.
(1. 입력) --> (2. N 에서 K 개를 뽑는다) --> (3. 출력)
두번째 함수의 꼴은 어떠한 형태가 되어야 할까요?
입력 : n, k
출력 : list
파이선이나 자바라면와 같이 list 를 쓸 수 있다면,
list random_select_from(n, k)
C 의 경우에는
int** random_select_from(int n, int k)
또는
void random_select(int n, int k, int *list)
첫번째 경우에는 리턴 되는 배열은 함수내에서 malloc 을 사용해서 리턴할 수 있습니다.
두번째는 그냥 호출부에서 list 의 크기를 k 개로 잡아서 호출하는 것입니다.
지금과 같은 경우에는 두번째 방법이 좀 더 편합니다. (** 는 거부감이 듭니다)
중요한 것은 언어에 따라서 함수의 꼴이 차이가 난다는 점이고,
C 는 그러한 면에서 유연성이 떨어집니다.
파이선 자바스크립트 루비 등의 언어는 기본적으로 리스트, 딕셔너리를 가지고 있습니다.
자바의 경우는 기본형은 아니지만 라이브러리에서 충분히 지원하니 사용법이 까다롭긴 해도 쓸만 합니다.
C 에서도 라이브러리를 쓰면 비슷하게 쓸 수 있습니만,
DRY (Do not repeat yourself : 있는 것을 또 만들지 말라)라는 말이 있지요.
인터넷 어디엔가 C 에서도 리스트와 같이 쓸 수 있도록 만든 라이브러리가 있을 겁니다. (반드시)
함수의 테스트는 어떻게 하면 될까요? (유닛테스트)
list 의 모든 원소는 중복되지 않아야 하며, 갯수는 k개 (이하)여야 한다.
list 의 모든 원소는 n 보다 작거나 같아야 한다.
위 과정을 N 번 반복해서 N 번 다 통과하면 유닛테스트가 통과하는 것으로 한다.
파이선 unittest 나 자바 junit 등을 이용해서 테스트를 만들면
random_select_from 함수는 만들 수 있을 것 같습니다.
글이 좀 길어져서, 테스트와 리팩토링은 1회 더 진행하도록 하겠습니다.
감사합니다.
- 내가 관리할 수 있는 코드량은? https://steemit.com/kr-dev/@agile/good-programmer-1
- HOWTO be Professional https://steemit.com/kr-dev/@agile/good-programmer-2-howto-be-professional
- 최소화 하기 https://steemit.com/kr-dev/@agile/good-programmer-3
- 설계하고 테스트 하기
- 테스트와 리팩토링