티스토리 뷰
어떤 유한한 집합이 주어지고, 여기에서 랜덤하게 중복없이 n개의 원소를 골라내는 작업을 구현해보자. 가장 간단하게 생각한다면 다음과 같은 알고리듬을 생각할 수 있다.
- 먼저 골라낼 원소를 가리키는 난수값을 발생시킨다.
- 1의 난수가 가리키는 집합의 원소를 고른다.
- 이 때 고르게 된 값이 이전에 뽑은 값과 중복되는지를 체크한다. 만약 한 번이라도 뽑았던 값이라면 버리고, 그렇지 않은 경우 결과에 추가한다.
- 1~3의 과정을 결과 집합의 크기가 n이 될때까지 반복한다.
로또 번호는 1~45 사이의 범위가 될 수 있기 때문에 random.randint(1, 45)
를 통해서 랜덤하게 고를 수 있다.
from random import randint
result = []
while len(result) < 6:
a = randint(1, 45)
if a not in result:
result.append(a)
이 때 result 가 리스트라면 in 연산은 O(n)의 복잡도를 가진다. 만약 result가 set 타입이라면 in 연산이 O(1)이 될 것이므로 조금의 성능 향상을 기대할 수 있다.
그런데 굳이 이렇게 반복을 직접 하지 않더라도 random 모듈에는 sample 이라는 함수가 존재한다. sample 함수는 주어진 집합에서 n 개의 원소를 중복없이 샘플링한다.(단, 같은 원소를 두 번 뽑지 않을 뿐이지 원래 집합에 중복된 원소가 있다면 결과에도 중복된 값이 들어갈 수 있다.)
from random import sample
xs = sample(range(1, 46), 6)
# xs = [15, 2, 29, 42, 9, 22]
조금 더 깊이
이번에는 뽑게되는 숫자에 특정한 규칙을 추가해보자. 뽑히는 숫자 6개 중에서 홀수/짝수의 비율이 3:3 이거나 2:4 혹은 4:2 가 되도록 하는 것이다. 이를 위해서는 다음과 같이 샘플링을 하면 된다.
- 먼저 홀수, 짝수는 각각 최소 2개씩은 샘플링된다.
- 1에서 4개를 뽑아 놓은 뒤, 홀/짝 구분 없이 전체 집합에서 중복 없이 2개를 샘플링한다.
- 1, 2의 합집합이 최종 결과가 된다.
따라서 홀수, 짝수의 집합을 set
으로 만들고, 여기서 샘플링한 결과를 다시 set으로 만들어서 채워나간다.
from random import sample
evens = set(range(2, 46, 2))
odds = set(range(1, 46, 2))
x = set(sample(evens, 2))
x |= set(sample(odds, 2))
x |= set(sample((odds | evens) - x, 2))
set을 사용하면 |
(합집합), &
(교집합), -
(차집합) 및 ^
(대칭차집합) 연산을 사용할 수 있다. 이 때 각 연산은 set 객체의 .union()
, .intersection()
, .difference()
, .symmetric_difference()
에 해당한다.
'숙제는 지식즐' 카테고리의 다른 글
윤년을 체크하는 방법 (0) | 2019.10.26 |
---|---|
[파이썬] 숫자를 한글로 읽는 함수 (0) | 2017.04.12 |
- Total
- Today
- Yesterday
- ipython-notebook
- sorted
- 복수기준정렬
- dict
- 튜플언패킹
- python list
- leapYear
- 이중리스트를 사용하지 않기
- Python
- locals()
- 정렬기준
- jupyter-notebook
- 반복자
- 파이썬
- globals()
- 단어 빈도수
- Lambda
- 사전
- 파이썬노트북
- 표준입력
- 함수형
- 변경가능
- 리눅스
- 정렬키
- iterable
- short_circuit
- mutability
- 리스트
- 우분투
- 파일입출력
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |