기본 자료형: 집합과 사전

집합

set μžλ£Œν˜•μ€ 집합에 ν•΄λ‹Ήν•˜λŠ” μžλ£Œν˜•μ΄λ©°, μˆ˜ν•™μ—μ„œ 배운 집합 κ°œλ…κ³Ό λ™μΌν•˜λ‹€.

  • μ›μ†Œλ“€ μ‚¬μ΄μ˜ μˆœμ„œκ°€ μ—†λ‹€.
  • μ€‘λ³΅λœ μ›μ†Œλ₯Ό μΈμ •ν•˜μ§€ μ•ŠλŠ”λ‹€.
In [1]:
primes_below_10 = {2, 3, 7, 5, 7, 3}
primes_below_10
Out[1]:
{2, 3, 5, 7}

μ›μ†Œμ˜ κ°œμˆ˜λŠ” len ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ ν™•μΈν•œλ‹€.

In [2]:
len(primes_below_10)
Out[2]:
4

곡집합은 set()으둜 μƒμ„±ν•˜λ©°, μ›μ†Œ μΆ”κ°€λŠ” add λ©”μ†Œλ“œλ₯Ό ν™œμš©ν•œλ‹€.

In [3]:
s = set()
s.add(1)
s.add(2)
s.add(2)

print(s)
{1, 2}

μ›μ†Œμ˜ ν¬ν•¨μ—¬λΆ€λŠ” in μ—°μ‚°μžλ₯Ό ν™œμš©ν•˜μ—¬ ν™•μΈν•œλ‹€.

In [4]:
2 in s
Out[4]:
True
In [5]:
3 in s
Out[5]:
False

집합 자료형 사용 이유

예제

λ¦¬μŠ€νŠΈμ— μ€‘λ³΅μœΌλ‘œ ν¬ν•¨λœ ν•­λͺ©μ„ μ‰½κ²Œ μ œκ±°ν•  수 μžˆλ‹€.

In [6]:
item_list = [1, 2, 3, 1, 2, 3]

item_set = set(item_list) 
distinct_item_list = list(item_set)

print(distinct_item_list)
[1, 2, 3]

예제

λ¦¬μŠ€νŠΈμ— μ€‘λ³΅μœΌλ‘œ ν¬ν•¨λœ ν•­λͺ©μ΄ μ‘΄μž¬ν•˜λŠ”κ°€λ₯Ό μ‰½κ²Œ νŒλ‹¨ν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, μ•„λž˜ ν•¨μˆ˜λŠ” 쀑볡 ν•¨μˆ˜μ˜ 포함여뢀λ₯Ό νŒλ‹¨ν•΄μ€€λ‹€.

In [7]:
def has_duplicates(t):
    return len(set(t)) < len(t)
In [8]:
has_duplicates(item_list)
Out[8]:
True

예제

길이가 맀우 κΈ΄ 리슀트λ₯Ό λŒ€μƒμœΌλ‘œ ν•­λͺ©μ˜ μ‘΄μž¬μ—¬λΆ€λ₯Ό νŒλ‹¨ν•  λ•Œ 집합 μžλ£Œν˜•μœΌλ‘œ ν˜•λ³€ν™˜μ„ ν•˜λ©΄ 맀우 λΉ λ₯΄κ²Œ ν•΄κ²°ν•  수 μžˆλ‹€.

In [9]:
hundreds_of_other_words = []  # 맀우 κΈ΄ 리슀트라 μƒμƒν•œλ‹€.
stopwords_list = ["a", "an", "at"] \
                + hundreds_of_other_words + ["yet", "you"]

print("zip" in stopwords_list)     # 확인 과정이 λŠλ¦¬λ‹€.

stopwords_set = set(stopwords_list)
print("zip" in stopwords_set)      # 맀우 λΉ λ₯΄κ²Œ ν™•μΈν•œλ‹€.
False
False

예제

뢀뢄집합 관계λ₯Ό μ΄μš©ν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, μ•„λž˜ ν•¨μˆ˜λŠ” 첫째 인자의 λ¦¬μŠ€νŠΈμ— ν¬ν•¨λœ λͺ¨λ“  μ›μ†Œκ°€, λ‘˜μ§Έ 인자의 λ¦¬μŠ€νŠΈμ— ν•­λͺ©μœΌλ‘œ ν¬ν•˜λ˜λŠ”μ§€ μ—¬λΆ€λ₯Ό νŒλ‹¨ν•œλ‹€.

주의: <= μ—°μ‚°μžλŠ” 집합을 λŒ€μƒμœΌλ‘œ ν•  경우 뢀뢄집합 관계λ₯Ό κ²°μ •ν•œλ‹€.

In [10]:
def sublist(list1, list2):
    return set(list1) <= set(list2)
In [11]:
sublist(item_list, distinct_item_list)
Out[11]:
True

사전

μ•ˆλ‚΄: Think Python 11μž₯ λ‚΄μš©μ˜ 일뢀λ₯Ό λ²ˆμ—­ 및 μš”μ•½μˆ˜μ •ν•˜μ—¬ μ •λ¦¬ν•œ λ‚΄μš©μž…λ‹ˆλ‹€.

사전 μžλ£Œκ°’μ€ μΌμ’…μ˜ μŒλ“€μ˜ 집합이며, 각 μŒμ€ ν‚€(key)와 κ°’(value)으둜 이루어져 μžˆλ‹€.

  • ν‚€(key): μ˜μ–΄μ‚¬μ „μ˜ 각 μ˜μ–΄λ‹¨μ–΄μ— 해당함.
  • κ°’(value): νŠΉμ • μ˜μ–΄λ‹¨μ–΄μ˜ λœ»μ— 해당함.

예λ₯Ό λ“€μ–΄, μ „μžμ˜μ–΄μ‚¬μ „μ—μ„œ 'school'μ΄λž€ λ‹¨μ–΄μ˜ λœ»μ„ 물으면 '학ꡐ'λΌλŠ” λœ»μ„ μ•Œλ €μ£ΌλŠ”λ° μ—¬κΈ°μ„œ 'school'이 킀에 ν•΄λ‹Ήν•˜κ³  '학ꡐ'κ°€ 값에 ν•΄λ‹Ήν•œλ‹€. λ”°λΌμ„œ μ „μžμ˜μ–΄μ‚¬μ „μ€ μ΄λŸ¬ν•œ 킀와 κ°’λ“€μ˜ μŒμ„ 무수히 많이 λͺ¨μ•„놓은 집합이라고 생각할 수 μžˆλ‹€.

항목

사전에 ν¬ν•¨λœ ν•­λͺ©μ€ 킀와 κ°’μœΌλ‘œ 이루어진 μŒμ΄λ‹€. 각각의 ν•­λͺ©μ€ 킀와 κ·Έ 킀와 μ—°κ΄€λœ 값듀에 λŒ€ν•œ 정보라고 μ΄ν•΄ν•˜λ©΄ λœλ‹€.

μ—¬κΈ°μ„œλŠ” μ˜ν•œμ‚¬μ „μ„ μƒμ„±ν•˜λŠ” 예제λ₯Ό 톡해 사전 μžλ£Œν˜•μ˜ ν™œμš©μ„ μ„€λͺ…ν•˜κ³ μž ν•œλ‹€.

빈 사전 생성

λ¨Όμ € 빈 사전을 μƒμ„±ν•œλ‹€.

빈 사전을 μƒμ„±ν•˜λ €λ©΄ dict ν•¨μˆ˜λ₯Ό ν™œμš©ν•˜κ±°λ‚˜ λ‹¨μˆœνžˆ μ•„λž˜μ™€ 같이 μ„ μ–Έν•˜λ©΄ λœλ‹€.

In [12]:
eng2kr = dict()
print(eng2kr)
{}

λ˜λŠ”

In [13]:
eng2kr = {}
print(eng2kr)
{}

주의: μ€‘κ΄„ν˜Έ({})λŠ” 빈 λ”•μ…”λ„ˆλ¦¬λ₯Ό λ‚˜νƒ€λ‚Έλ‹€.

항목 추가

사전에 ν•­λͺ©μ„ μΆ”κ°€ν•˜λ €λ©΄ 킀와 κ°’μ˜ 관계λ₯Ό λŒ€κ΄„ν˜Έ μ—°μ‚°μžλ₯Ό μ΄μš©ν•˜μ—¬ μ§€μ •ν•˜λ©΄ λœλ‹€. 예λ₯Ό λ“€μ–΄, μ˜λ‹¨μ–΄ oneκ³Ό ν•œκΈ€ 뜻 일, ν•˜λ‚˜λ₯Ό μ—°κ΄€μ§€μœΌλ €λ©΄ λ‹€μŒκ³Ό 같이 ν•œλ‹€.

In [14]:
eng2kr['one'] = '일, ν•˜λ‚˜'

사전에 ν¬ν•¨λœ λ‚΄μš©μ„ ν™•μΈν•˜λ©΄ 킀와 κ°’ 사이에 콜둠이 λ“€μ–΄κ°„ 킀와 κ°’μ˜ μŒμ„ λ³Ό 수 μžˆλ‹€.

In [15]:
print(eng2kr)
{'one': '일, ν•˜λ‚˜'}

ν•­λͺ©μ„ ν•˜λ‚˜ 더 μΆ”κ°€ν•΄λ³΄μž.

In [16]:
eng2kr['three'] = 'μ‚Ό, μ…‹'
In [17]:
print(eng2kr)
{'one': '일, ν•˜λ‚˜', 'three': 'μ‚Ό, μ…‹'}

사전 선언

μ•„λž˜μ™€ 같이 사전을 λ°”λ‘œ μ„ μ–Έν•  μˆ˜λ„ μžˆλ‹€.

In [18]:
dict_exp = {'one':'일, ν•˜λ‚˜', 'two':'이, λ‘˜', 'three':'μ‚Ό, μ…‹'}
In [19]:
print(dict_exp)
{'one': '일, ν•˜λ‚˜', 'two': '이, λ‘˜', 'three': 'μ‚Ό, μ…‹'}

항목의 순서

'eng2kr'에 ν•­λͺ©μ„ ν•˜λ‚˜ 더 μΆ”κ°€ν•΄λ³΄μž.

In [20]:
eng2kr['two'] = '이, λ‘˜'
In [21]:
print(eng2kr)
{'one': '일, ν•˜λ‚˜', 'three': 'μ‚Ό, μ…‹', 'two': '이, λ‘˜'}

μ˜μ–΄μ‚¬μ „μ— μ–΄λ–€ 단어가 λͺ‡ λ²ˆμ§Έμ— μœ„μΉ˜ν•˜λŠ”κ°€λŠ” μ „ν˜€ μ€‘μš”ν•˜μ§€ μ•Šλ‹€. λŒ€μ‹ μ— μ–΄λ–€ ν‚€κ°€ μ‚¬μš©λ˜μ—ˆλŠ”κ°€λ§Œ μ€‘μš”ν•˜λ‹€.

대괄호([]) 연산자

λŒ€κ΄„ν˜Έ μ—°μ‚°μžλŠ” ν•­λͺ©μ„ μΆ”κ°€ν•  λ•Œμ™€ ν•¨κ²Œ ν•­λͺ©μ„ ν™•μΈν•˜κ±°λ‚˜ μ—…λ°μ΄νŠΈ ν•  λ•Œλ„ μ‚¬μš©ν•œλ‹€. 예λ₯Ό λ“€μ–΄, 'one'에 λŒ€μ‘ν•˜λŠ” 값을 ν™•μΈν•˜κ³ μž ν•˜λ©΄ λ‹€μŒκ³Ό 같이 λŒ€κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜λŠ” 인덱싱을 μ΄μš©ν•œλ‹€.

In [22]:
print(eng2kr['one'])
일, ν•˜λ‚˜

킀와 μ—°κ΄€λœ 값을 μ—…λ°μ΄νŠΈ ν•˜λ €λ©΄ μƒˆλ‘­κ²Œ μ§€μ •ν•˜λ©΄ λœλ‹€.

In [23]:
eng2kr['one'] = '일, ν•˜λ‚˜, ν•œλ²ˆ, μœ μΌν•œ'
print(eng2kr)
{'one': '일, ν•˜λ‚˜, ν•œλ²ˆ, μœ μΌν•œ', 'three': 'μ‚Ό, μ…‹', 'two': '이, λ‘˜'}

λ§Œμ•½ ν‚€κ°€ 사전에 μ‚¬μš©λ˜μ§€ μ•Šμ•˜μœΌλ©΄ 였λ₯˜(KeyError)κ°€ λ°œμƒν•œλ‹€.

In [24]:
print(eng2kr['four'])
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-24-bb50ad42a120> in <module>
----> 1 print(eng2kr['four'])

KeyError: 'four'

'len' 함수

사전에 ν¬ν•¨λœ ν•­λͺ©μ˜ 개수λ₯Ό ν™•μΈμ‹œμΌœμ£ΌλŠ” ν•¨μˆ˜μ΄λ‹€.

In [25]:
len(eng2kr)
Out[25]:
3

'in' 연산자

νŠΉμ • ν‚€κ°€ 사전에 μ‚¬μš©λ˜μ—ˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•œλ‹€.

In [26]:
'one' in eng2kr
Out[26]:
True
In [27]:
'four' in eng2kr
Out[27]:
False

사전 자료형 메서드

keys 메서드

사전에 μ‚¬μš©λœ 킀듀을 λͺ¨λ‘ λͺ¨μ•„μ„œ λ¦¬μŠ€νŠΈμ™€ λΉ„μŠ·ν•œ μžλ£Œν˜•μ„ λ§Œλ“€μ–΄μ„œ λ¦¬ν„΄ν•œλ‹€.

주의: λ¦¬μŠ€νŠΈμ™€λŠ” λ‹€λ₯΄μ§€λ§Œ 맀우 λΉ„μŠ·ν•˜λ‹€.

In [28]:
keys = eng2kr.keys()

print(keys)
dict_keys(['one', 'three', 'two'])

μ•„λž˜ 두 μ½”λ“œλŠ” λ™μΌν•œ 일을 μˆ˜ν–‰ν•œλ‹€.

In [29]:
'one' in eng2kr
Out[29]:
True
In [30]:
'one' in eng2kr.keys()
Out[30]:
True

values 메서드

사전에 μ‚¬μš©λœ 값듀을 λͺ¨λ‘ λͺ¨μ•„μ„œ λ¦¬μŠ€νŠΈμ™€ λΉ„μŠ·ν•œ μžλ£Œν˜•μ„ λ§Œλ“€μ–΄μ„œ λ¦¬ν„΄ν•œλ‹€.

주의: λ¦¬μŠ€νŠΈμ™€λŠ” λ‹€λ₯΄μ§€λ§Œ 맀우 λΉ„μŠ·ν•˜λ‹€.

In [31]:
values = eng2kr.values()
print(values)
dict_values(['일, ν•˜λ‚˜, ν•œλ²ˆ, μœ μΌν•œ', 'μ‚Ό, μ…‹', '이, λ‘˜'])

κ°’μœΌλ‘œ μ‚¬μš©λ˜μ—ˆλŠ”κ°€ μ—¬λΆ€λ₯Ό μ΄μš©ν•˜λ €λ©΄ values λ©”μ„œλ“œλ₯Ό ν™œμš©ν•˜λ©΄ λœλ‹€.

In [32]:
'이' in eng2kr.values()
Out[32]:
False
In [33]:
'사' in eng2kr.values()
Out[33]:
False

items 메서드

사전에 ν¬ν•¨λœ ν•­λͺ©λ“€μ„ μˆœμ„œμŒλ“€μ˜ 리슀트둜 λ³€ν™˜ν•œλ‹€. 각각의 μˆœμ„œμŒμ€ 킀와 κ°’μœΌλ‘œ 이루어진, 즉 길이가 2인 νŠœν”Œμ΄λ‹€.

주의: λ¦¬μŠ€νŠΈμ™€λŠ” λ‹€λ₯΄μ§€λ§Œ 맀우 λΉ„μŠ·ν•˜λ‹€.

In [34]:
values = eng2kr.items()
print(values)
dict_items([('one', '일, ν•˜λ‚˜, ν•œλ²ˆ, μœ μΌν•œ'), ('three', 'μ‚Ό, μ…‹'), ('two', '이, λ‘˜')])

μ‚¬μ „μ˜ ν•­λͺ©μ„ νŠœν”Œλ‘œ ν•˜λ‚˜μ”© ν™•μΈν•΄λ³΄μž. ν•­λͺ©λ“€μ΄ 길이가 2인 νŠœν”Œλ‘œ κ΅¬μ„±λ˜κΈ°μ— λ³€μˆ˜ 두 κ°œμ— 각각 ν• λ‹Ήν•  수 μžˆλ‹€.

In [35]:
for eng, kor in eng2kr.items():
    print(f"{eng}의 λœ»μ€ {kor}μž…λ‹ˆλ‹€.")
one의 λœ»μ€ 일, ν•˜λ‚˜, ν•œλ²ˆ, μœ μΌν•œμž…λ‹ˆλ‹€.
three의 λœ»μ€ μ‚Ό, μ…‹μž…λ‹ˆλ‹€.
two의 λœ»μ€ 이, λ‘˜μž…λ‹ˆλ‹€.

μ˜μ–΄ 단어에 μ—¬λŸ¬ 뜻이 μžˆμ„ 수 있기 λ•Œλ¬Έμ— 그것을 보닀 μƒμ„Ένžˆ 보여쀄 μˆ˜λ„ μžˆλ‹€. 그러기 μœ„ν•΄ λ¬Έμžμ—΄μ„ splitκ³Ό join λ©”μ„œλ“œλ₯Ό ν™œμš©ν•œλ‹€.

μ°Έκ³ : split/join λ©”μ„œλ“œμ˜ ν™œμš©μ€ λ¬Έμžμ—΄ λ‚˜λˆ„κΈ°/ν•©μΉ˜κΈ°μ— μ’€ 더 λ‹€μ–‘ν•œ μ˜ˆμ œκ°€ 있음.

In [36]:
for eng, kor in eng2kr.items():
    meaning = kor.split(', ')
    print(f"{eng}의 λœ»μ€ {' λ˜λŠ” '. join(meaning)}μž…λ‹ˆλ‹€.")
one의 λœ»μ€ 일 λ˜λŠ” ν•˜λ‚˜ λ˜λŠ” ν•œλ²ˆ λ˜λŠ” μœ μΌν•œμž…λ‹ˆλ‹€.
three의 λœ»μ€ μ‚Ό λ˜λŠ” μ…‹μž…λ‹ˆλ‹€.
two의 λœ»μ€ 이 λ˜λŠ” λ‘˜μž…λ‹ˆλ‹€.

예제: 다이빙 기록과 사전 자료형

μ—°κ΄€λ°°μ—΄ ν™œμš©μ—μ„œ 닀룬 닀이빙 기둝을 사전 μžλ£Œν˜•μœΌλ‘œ μ €μž₯ν•˜λŠ” ν•¨μˆ˜λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

In [37]:
def scoreDict(fileName):
    try:
        result_f = open(fileName, 'r') 
    except FileNotFoundError:
        print("μ—΄κ³ μž ν•˜λŠ” 파일이 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.")

    score_dict = dict() 

    for line in result_f: 
        name, score = line.split() 
        try:
            score_dict[float(score)] = name
        except:
            continue
    result_f.close() 

    return score_dict

μœ„ ν•¨μˆ˜λ₯Ό 5m 닀이빙 기둝과 ν•¨κ»˜ ν˜ΈμΆœν•˜λ©΄ 기둝을 사전 μžλ£Œν˜•μœΌλ‘œ μ €μž₯ν•  수 μžˆλ‹€.

In [38]:
scores = scoreDict('./data/results5m.txt')
print(scores)
{7.13: 'κΆŒμ€€κΈ°', 8.55: 'κΉ€μ„Έμœ€', 9.02: 'λ‚˜μ§„μ„œ', 8.35: 'λ§ˆλ™νƒ', 7.86: 'μ„œκΈΈμ„', 8.17: 'μ΄μ€€μš©', 9.33: '이차승', 7.11: 'μ°¨μŠΉμ—°', 8.57: 'ν‘œλ°©ν˜Έ', 8.93: 'ν•œμ„μ€€'}

그런데 scoreDict ν•¨μˆ˜λŠ” μ„ μˆ˜λ“€μ˜ 성적을 ν‚€λ‘œ, ν•΄λ‹Ή 성적을 λ‚Έ μ„ μˆ˜ 이름을 κ°’μœΌλ‘œ μ‚¬μš©ν•œλ‹€. κ·Έλ ‡κ²Œ ν•œ μ΄μœ λŠ” 정렬을 μ΄μš©ν•˜μ—¬ λ“±μˆ˜λ₯Ό μ •ν•˜κΈ° μœ„ν•΄μ„œ μ˜€λ‹€.

μ—¬κΈ°μ„œλŠ” μ„ μˆ˜μ΄λ¦„μ„ ν‚€λ‘œ, ν•΄λ‹Ή μ„ μˆ˜μ˜ 성적을 κ°’μœΌλ‘œ ν™œμš©ν•΄λ³΄μž. 그러기 μœ„ν•΄ scoreDictλ₯Ό μ•„λž˜μ™€ 같이 μ•½κ°„ μˆ˜μ •ν•˜λ©΄ λœλ‹€.

In [39]:
def nameScoreDict(fileName):
    try:
        result_f = open(fileName, 'r') 
    except FileNotFoundError:
        print("μ—΄κ³ μž ν•˜λŠ” 파일이 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.")

    nameScore_dict = dict()                   # 이름을 ν‚€λ‘œ μ‚¬μš© μ•”μ‹œ

    for line in result_f: 
        name, score = line.split() 
        try:
            nameScore_dict[name] = float(score)   # 이름을 ν‚€λ‘œ, 성적을 κ°’μœΌλ‘œ.
        except:
            continue
    result_f.close() 

    return nameScore_dict

5m 닀이빙 기둝을 λ‹€μ‹œ μ½μ–΄μ˜¨λ‹€.

In [40]:
nameScores = nameScoreDict('./data/results5m.txt')
print(nameScores)
{'κΆŒμ€€κΈ°': 7.13, 'κΉ€μ„Έμœ€': 8.55, 'λ‚˜μ§„μ„œ': 9.02, 'λ§ˆλ™νƒ': 8.35, 'μ„œκΈΈμ„': 7.86, 'μ΄μ€€μš©': 8.17, '이차승': 9.33, 'μ°¨μŠΉμ—°': 7.11, 'ν‘œλ°©ν˜Έ': 8.57, 'ν•œμ„μ€€': 8.93}

이제 μ„ μˆ˜ 이름을 μ§€μ •ν•˜λ©΄ ν•΄λ‹Ή μ„ μˆ˜μ˜ 점수λ₯Ό 인덱싱을 ν™œμš©ν•˜μ—¬ 확인할 수 μžˆλ‹€.

In [41]:
nameScores['κΆŒμ€€κΈ°']
Out[41]:
7.13
In [42]:
nameScores['μ΄μ€€μš©']
Out[42]:
8.17

반복문과 사전

사전을 for λ°˜λ³΅λ¬Έμ— μ‚¬μš©ν•˜λ©΄ μ‚¬μ „μ˜ ν‚€λ₯Ό κΈ°μ€€μœΌλ‘œ λ°˜λ³΅λ¬Έμ„ μ‹€ν–‰ν•œλ‹€.

μ•„λž˜ μ˜ˆμ œλŠ” nameScores에 μ €μ •λœ 값듀을 파일의 λ‚΄μš©κ³Ό λ™μΌν•œ λͺ¨μ–‘μœΌλ‘œ ν•˜λ‚˜μ”© 좜λ ₯ν•œλ‹€.

In [43]:
for key in nameScores:
    print(key, nameScores[key])
κΆŒμ€€κΈ° 7.13
κΉ€μ„Έμœ€ 8.55
λ‚˜μ§„μ„œ 9.02
λ§ˆλ™νƒ 8.35
μ„œκΈΈμ„ 7.86
μ΄μ€€μš© 8.17
이차승 9.33
μ°¨μŠΉμ—° 7.11
ν‘œλ°©ν˜Έ 8.57
ν•œμ„μ€€ 8.93

μ•„λž˜ μ½”λ“œλŠ” μœ„ μ½”λ“œμ™€ λ™μΌν•œ κΈ°λŠ₯을 μˆ˜ν–‰ν•œλ‹€.

In [44]:
for key in nameScores.keys():
    print(key, nameScores[key])
κΆŒμ€€κΈ° 7.13
κΉ€μ„Έμœ€ 8.55
λ‚˜μ§„μ„œ 9.02
λ§ˆλ™νƒ 8.35
μ„œκΈΈμ„ 7.86
μ΄μ€€μš© 8.17
이차승 9.33
μ°¨μŠΉμ—° 7.11
ν‘œλ°©ν˜Έ 8.57
ν•œμ„μ€€ 8.93

예제: 카운터

λ¬Έμžμ—΄μ— μ‚¬μš©λœ 각각의 λ¬Έμžκ°€ λͺ‡ λ²ˆμ”© μ‚¬μš©λ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” ν•¨μˆ˜λ₯Ό 사전을 μ΄μš©ν•˜μ—¬ μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.

In [45]:
def histogram(word):
    counts = dict()
    for c in word: 
        if c not in counts:   # μ•ŒνŒŒλ²³μ΄ 처음 μ‚¬μš©λœ 경우
            counts[c] = 1     # counts 사전에 킀와 카운트 κ°’ μΆ”κ°€
        else:                 # μ•ŒνŒŒλ²³μ΄ 이미 μ‚¬μš©λœ 경우
            counts[c] += 1    # 기쑴의 카운트 κ°’ 1 증가
    return counts
In [46]:
histogram('HelloPython')
Out[46]:
{'H': 1, 'e': 1, 'l': 2, 'o': 2, 'P': 1, 'y': 1, 't': 1, 'h': 1, 'n': 1}

μ•„λž˜μ— μ •μ˜λœ ν•¨μˆ˜ print_histλŠ” 각 킀와 λŒ€μ‘ν•˜λŠ” 값을 μΈμ‡„ν•œλ‹€.

In [47]:
def print_hist(a_dict):
    for key in a_dict:
        print(key, a_dict[key])

μ•žμ„œ κ΅¬ν˜„ν•œ 'histogram' ν•¨μˆ˜μ˜ 리턴값을 ν™œμš©ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

In [48]:
countHelloPython = histogram('HelloPython')
print_hist(countHelloPython)
H 1
e 1
l 2
o 2
P 1
y 1
t 1
h 1
n 1

동적계획, 리스트, 사전

피보나찌 수열

ν”Όλ³΄λ‚˜μ°Œ(Fibonacci) μˆ˜μ—΄μ€ μ•„λž˜μ™€ 같이 μ „κ°œλœλ‹€.

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...

즉, μˆ˜μ—΄μ˜ 첫째, λ‘˜μ§Έ ν•­λͺ©μ€ 1이며, μ…‹μ§Έ ν•­λͺ©μ€ 첫째와 λ‘˜μ§Έ ν•­λͺ©μ˜ ν•©, λ„·μ§Έ ν•­λͺ©μ€ λ‘˜μ§Έμ™€ μ…‹μ§Έ ν•­λͺ©μ˜ ν•©, λ“±μœΌλ‘œ μ§„ν–‰λœλ‹€. n이 2보닀 클 경우, 이λ₯Ό μΌλ°˜ν™”ν•˜λ©΄ (n) 번째 ν•­λͺ©μ€ (n-1) 번째 ν•­λͺ©κ³Ό (n-2) 번째 ν•­λͺ©μ˜ 합이며, 이λ₯Ό μˆ˜μ‹μœΌλ‘œ ν‘œν˜„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

fib(0)   = 1 
fib(1)   = 1 
fib(n) = fib(n-1) + fib(n-2)

μž¬κ·€ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜λ©΄ μ‰½κ²Œ fib ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  수 μžˆλ‹€.

In [49]:
def fib(n):
    if n in {0, 1}:
        return 1
    else:
        return fib(n-1) + fib(n-2)

μ‹€μ œλ‘œ 잘 μž‘λ™ν•˜λŠ” κ²ƒμœΌλ‘œ 보인닀.

In [50]:
fib(0)
Out[50]:
1
In [51]:
fib(1)
Out[51]:
1
In [52]:
fib(2)
Out[52]:
2
In [53]:
fib(3)
Out[53]:
3
In [54]:
fib(5)
Out[54]:
8
In [55]:
fib(10)
Out[55]:
89

그런데 40번째 ν”Όλ³΄λ‚˜μ°Œ 수 계산이 올래 걸릴 수 μžˆλ‹€. μ§€κΈˆ μ‚¬μš©ν•˜λŠ” μ»΄ν“¨ν„°λ‘œ 20초 이상 κ±Έλ¦°λ‹€. ν˜„μž¬ μ‚¬μš©λœ 컴퓨터 사양은 λ‹€μŒκ³Ό κ°™λ‹€.

  • cpu: 3.6 GHz Quad-Core Intel Core i7
  • λ©”λͺ¨λ¦¬: 16 GB 2400 MHz DDR4

주의:

  • μ‹€ν–‰μ‹œκ°„μ„ μΈ‘μ •ν•˜κΈ° μœ„ν•΄ time λͺ¨λ“ˆμ˜ time ν•¨μˆ˜λ₯Ό ν™œμš©ν•œλ‹€.
  • int ν•¨μˆ˜λ₯Ό λΆ€λ™μ†Œμˆ˜μ μ„ 인자둜 μ‚¬μš©ν•˜λ©΄ μ†Œμˆ˜μ  μ΄ν•˜λ₯Ό 버린닀.
In [56]:
import time                              # time λͺ¨λ“ˆ 뢈러였기

start_time = time.time()                 # μ‹€ν–‰ μ‹œμž‘ μ‹œκ°„ κΈ°μ–΅
fib(39)
end_time = time.time()                   # μ‹€ν–‰ μ’…λ£Œ μ‹œκ°„ κΈ°μ–΅

elapsed_time = end_time - start_time
print(f'μ•½ {int(elapsed_time)}초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.')
μ•½ 26초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 1,000번째 ν”Όλ³΄λ‚˜μ°Œ 수λ₯Ό κ΅¬ν•˜λ €λŠ” μ‹œλ„λŠ” μ›¬λ§Œν•˜λ©΄ ν•˜μ§€ μ•ŠλŠ” 게 μ’‹λ‹€. λŒ€λΆ€λΆ„ 쀑간에 였λ₯˜κ°€ λ°œμƒν•˜κ±°λ‚˜ μ•„λ‹ˆλ©΄ 맀우 였래 걸릴 수 있기 λ•Œλ¬Έμ΄λ‹€. μ‹€μ œλ‘œ fib(n)을 κ³„μ‚°ν•˜κΈ° μœ„ν•΄ fib ν•¨μˆ˜λ₯Ό λŒ€λž΅ $2^{n-1}$번 ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€. 예λ₯Ό λ“€μ–΄, fib(5)λ₯Ό κ³„μ‚°ν•˜κΈ° μœ„ν•΄ fib ν•¨μˆ˜λ₯Ό 15번 ν˜ΈμΆœν–ˆλ‹€.

<κ·Έλ¦Ό 좜처: ν”Όλ³΄λ‚˜μ°Œ 수 κ³„μ‚°ν•˜κΈ°>

PythonTutor: ν”Όλ³΄λ‚˜μ°Œ μž¬κ·€ν•¨μˆ˜μ—μ„œ fib ν•¨μˆ˜μ˜ 인자λ₯Ό λ³€κ²½ν•΄ λ³΄λ©΄μ„œ 싀행을 μ‹œλ„ν•΄ 보면 계산을 μ–Όλ§ˆλ‚˜ 많이 ν•˜κ³ , 또 λ©”λͺ¨λ¦¬λ₯Ό μ–Όλ§ˆλ‚˜ 많이 μ‚¬μš©ν•˜λŠ”μ§€ 눈으둜 확인할 수 μžˆλ‹€.

참고둜 ν˜„μž¬ Python Tutorμ—μ„œ 인자둜 μ‚¬μš©ν•  수 μžˆλŠ” ν•œκ³„λŠ” 10이닀. μ‹€μ œλ‘œ

  • n = 9: 438번의 μˆ˜ν–‰ 단계 ν•„μš”
  • n = 10: 710번의 μˆ˜ν–‰ 단계 ν•„μš”

n > 10에 λŒ€ν•΄μ„œλŠ” PythonTutor μ„œλ²„μ˜ μ œν•œ λ•Œλ¬Έμ— μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.

동적계획과 리스트

μž¬κ·€λ‘œ κ΅¬ν˜„λœ fib ν•¨μˆ˜μ˜ 근본적인 λ¬Έμ œλŠ” PythonTutor μ˜ˆμ œμ—μ„œ 확인할 수 μžˆλ“―μ΄ 반볡적인 계산을 λ„ˆλ¬΄ 많이 ν•˜λŠ” 것이닀. 무엇보닀도 n=39와 같은 μž‘μ€ μΈμžμ— λŒ€ν•΄μ„œ 20초 이상 κ±Έλ¦¬λŠ” 계산은 λ¬Έμ œκ°€ 많으며, μ’€ 더 큰 μΈμžλŠ” μ•„μ˜ˆ 계산을 ν•  μˆ˜λ„ μ—†λ‹€.

이에 λŒ€ν•œ 해결책을 λ™μ κ³„νš(dynamic programming)이 μ œκ³΅ν•œλ‹€. λ™μ κ³„νšμ€ 반볡적인 계산을 ν•˜μ§€ μ•ŠλŠ”λ‹€. 예λ₯Ό λ“€μ–΄,fib(5)λ₯Ό κ³„μ‚°ν•˜λ €λ©΄ fib(4), fib(3), fib(2) fib(1), fib(0) 등을 νƒ‘λ‹€μš΄(top-down) λ°©μ‹μœΌλ‘œ 계산해야 ν•œλ‹€. ν•˜μ§€λ§Œ fib(0), fib(1), fib(2), fib(3), fib(4), fib(5) 등을 λ°”ν…€μ—…(bottom-up) λ°©μ‹μœΌλ‘œ κ³„μ‚°ν•˜μ—¬ μ €μž₯ν•˜λŠ” 방식을 μ‚¬μš©ν•˜λ©΄ 보닀 λΉ λ₯΄κ³  효율적으둜 계산할 수 μžˆλ‹€. 이런 방식을 λ™μ κ³„νšμ΄λΌ λΆ€λ₯Έλ‹€.

이제 λ™μ κ³„νš λ°©μ‹μœΌλ‘œ ν”Όλ³΄λ‚˜μ°Œ μˆ˜μ—΄μ„ κ³„μ‚°ν•˜λŠ” ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•΄λ³΄μž. 이미 κ³„μ‚°λœ ν”Όλ³΄λ‚˜μ°Œ 수λ₯Ό κΈ°μ–΅ν•˜κΈ° μœ„ν•΄ 리슀트λ₯Ό ν™œμš©ν•œλ‹€.

λ¨Όμ € μ•„λž˜μ™€ 같이 n 번째 ν”Όλ³΄λ‚˜μ°Œ 수λ₯Ό (n-1) 번 인덱슀의 κ°’μœΌλ‘œ μ €μž₯ν•˜λŠ” 방식을 μ‚¬μš©ν•  수 μžˆλ‹€.

In [57]:
def fibListLong(n):
    known_nums = [1, 1]                           # 첫번째, λ‘λ²ˆμž¬ ν”Όλ³΄λ‚˜μ°Œ 수
    for k in range(2, n+1):                        
        res = known_nums[k-1] + known_nums[k-2]   # (k+1) 번째 ν”Όλ³΄λ‚˜μ°Œ 수 계산
        known_nums.append(res)                    # k번 인덱슀의 값이 (k+1) 번째 ν”Όλ³΄λ‚˜μ°Œ 수
    return known_nums[-1]                         # λ§ˆμ§€λ§‰ ν•­λͺ© 좜λ ₯

μœ„μ™€ 같이 ν•˜λ©΄ 40번째 ν”Όλ³΄λ‚˜μ°Œ 수λ₯Ό λ‹¨λ²ˆμ— ꡬ해쀀닀.

In [58]:
fibListLong(39)
Out[58]:
102334155

심지어 1,001 번째 값도 금방 κ΅¬ν•œλ‹€.

In [59]:
fibListLong(1000)
Out[59]:
70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501

μ‹€ν—˜ κ²°κ³Ό μ‹­λ§Œλ²ˆ μ§Έ ν”Όλ³΄λ‚˜μ°Œ μˆ˜λ„ 금방 κ΅¬ν•œλ‹€.

In [60]:
start_time = time.time()                
fibNum100000 = fibListLong(100000)
end_time = time.time()                  

elapsed_time = end_time - start_time
print(f'μ•½ {elapsed_time}초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.')
μ•½ 0.33864307403564453초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.

그런데 백만번째 ν”Όλ³΄λ‚˜μ°Œ μˆ˜λŠ” κ³„μ‚°ν•˜μ§€ λͺ»ν•œλ‹€. μ΄μœ λŠ” known_numsκ°€ κ°€λ¦¬ν‚€λŠ” 리슀트의 길이가 점점 κΈΈμ–΄μ§€λ©΄μ„œ λ™μ‹œμ— ν•­λͺ©μ— μ‚¬μš©λ˜λŠ” κ°’λ“€ μ—­μ‹œ 맀우 큰 μˆ˜κ°€ 되기 λ•Œλ¬Έμ΄λ‹€. μ‹€μ œλ‘œ μ‹­λ§ŒμΌλ²ˆμ§Έ ν”Όλ³΄λ‚˜μ°Œ μˆ˜λŠ” λ‹€μ„― 화면에 κ±Έμ³μ„œ ν‘œκΈ°λ  μ •λ„λ‘œ 크닀.

μœ„ ν•¨μˆ˜λ₯Ό μ•½κ°„ μ—…κ·Έλ ˆμ΄λ“œ ν•  수 μžˆλ‹€. ν”Όλ³΄λ‚˜μ°Œ 수λ₯Ό κ³„μ‚°ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ κ±°λŠ” 이전에 κ³„μ‚°λœ 두 개의 수 뿐이닀. λ”°λΌμ„œ κ·Έλ•ŒκΉŒμ§€μ˜ λͺ¨λ“  수λ₯Ό κΈ°μ–΅ν•  ν•„μš”κ°€ μ—†λ‹€. 이 아이디어λ₯Ό μ΄μš©ν•˜μ—¬ μ•„λž˜μ™€ 같이 κ΅¬ν˜„ν•˜λ©΄ 백만번째 ν”Όλ³΄λ‚˜μ°Œ μˆ˜λ„ 계산할 수 μžˆλ‹€.

In [61]:
def fibList(n):
    known_nums = [1, 1]                         # 첫번째, λ‘λ²ˆμž¬ ν”Όλ³΄λ‚˜μ°Œ 수
    for k in range(2, n+1):
        res = known_nums[1] + known_nums[0]     # μƒˆλ‘œμš΄ ν”Όλ³΄λ‚˜μ°Œ 수 계산
        known_nums[0] = known_nums[1]           # 리슀트 μ—…λ°μ΄νŠΈ
        known_nums[1] = res
    return known_nums[1]                        # λ‘˜μ§Έ ν•­λͺ© 좜λ ₯
In [62]:
fibList(1000)
Out[62]:
70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501

μ‹­λ§ŒμΌλ²ˆμ§Έ ν”Όλ³΄λ‚˜μ°Œ μˆ˜λ„ λˆˆκΉœλΉ‘ν•  사이에 κ³„μ‚°ν•œλ‹€. λ°”λ‘œ 좜λ ₯ν•˜λ©΄ λ„ˆλ¬΄ 큰 μˆ˜μ΄κΈ°μ— λ³€μˆ˜μ— ν• λ‹Ήν•˜λŠ” μ‹μœΌλ‘œ ν•΄μ„œ 계산이 κ°€λŠ₯ν•œμ§€λ§Œ ν™•μΈν•΄λ³΄μž.

In [63]:
start_time = time.time()
fibNum100000 = fibList(100000)
end_time = time.time()  

elapsed_time = end_time - start_time
print(f'μ•½ {elapsed_time}초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.')
μ•½ 0.19435954093933105초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.

백만일번째 ν”Όλ³΄λ‚˜μ°Œ μˆ˜λ„ 10μ—¬μ΄ˆ λ§Œμ— 계산해쀀닀.

In [64]:
start_time = time.time()
fibNum1M = fibList(1000000)
end_time = time.time()  

elapsed_time = end_time - start_time
print(f'μ•½ {elapsed_time}초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.')
μ•½ 10.604944944381714초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.

천만일번째 μˆ˜λŠ” κ½€ 였래 κ±Έλ¦°λ‹€. λͺ‡ λΆ„ 기닀렀도 계속 계산쀑이라 μ •μ§€μ‹œμΌ°λ‹€.

동적계획과 사전

μ•žμ„œ 길이가 2인 리슀트λ₯Ό μ‚¬μš©ν•˜μ—¬ ν”Όλ³΄λ‚˜μ°Œ 수λ₯Ό μ—…λ°μ΄νŠΈ ν•˜λ©΄μ„œ κ³„μ‚°ν•˜μ˜€λ‹€. λ™μΌν•œ 아이디어λ₯Ό 사전을 μ΄μš©ν•˜μ—¬ κ΅¬ν˜„ν•  수 μžˆλ‹€. μ‹€ν–‰ μ‹œκ°„κ³Ό λŠ₯λ ₯은 기본적으둜 fibList와 λ™μΌν•˜λ‹€.

In [65]:
def fibDict(n):
    known_nums = {0:1, 1:1}
    for k in range(2, n+1):
        res = known_nums[1] + known_nums[0]
        known_nums[0] = known_nums[1]
        known_nums[1] = res
    return known_nums[1]
In [66]:
start_time = time.time()
fibNum100000 = fibDict(100000)
end_time = time.time()  

elapsed_time = end_time - start_time
print(f'μ•½ {elapsed_time}초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.')
μ•½ 0.13864493370056152초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.
In [67]:
start_time = time.time()
fibNum1M = fibDict(1000000)
end_time = time.time()  

elapsed_time = end_time - start_time
print(f'μ•½ {elapsed_time}초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.')
μ•½ 10.598241329193115초 κ±Έλ ΈμŠ΅λ‹ˆλ‹€.

처리속도: in 연산자

λ¦¬μŠ€νŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” in μ—°μ‚°μžμ™€ μ‚¬μ „μ—μ„œ μ‚¬μš©λ˜λŠ” in μ—°μ‚°μžλŠ” λ‚΄λΆ€μ μœΌλ‘œ μ„œλ‘œ λ‹€λ₯΄κ²Œ μž‘λ™ν•œλ‹€. μ—¬κΈ°μ„œλŠ” μ²˜λ¦¬μ†λ„ κ΄€λ ¨ν•΄μ„œλ§Œ μ„€λͺ…ν•œλ‹€.

  • 리슀트의 in μ—°μ‚°μž 검색 속도: ν‰κ· μ μœΌλ‘œ μ‚¬μš©λ˜λŠ” 리슀트의 길이에 λΉ„λ‘€
  • μ‚¬μ „μ˜ in μ—°μ‚°μž 검색 속도: ν‰κ· μ μœΌλ‘œ μ‚¬μ „μ˜ 길이에 μƒκ΄€μ—†μŒ. λ‹€λ§Œ μ΅œμ•…μ˜ 경우 길이에 λΉ„λ‘€.

μžμ„Έν•œ λ‚΄μš©μ€ μ‹œκ°„ λ³΅μž‘λ„λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€.

연습문제

  1. μ•„λž˜ 기쀀을 λ§Œμ‘±ν•˜λŠ” has_duplicates ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•˜λΌ.

    • ν•˜λ‚˜μ˜ 리슀트λ₯Ό μž…λ ₯λ°›λŠ”λ‹€.
    • λ¦¬μŠ€νŠΈμ— νŠΉμ • ν•­λͺ©μ΄ 두 번 μ‚¬μš©λ˜λ©΄ Trueλ₯Ό 그렇지 μ•ŠμœΌλ©΄ Falseλ₯Ό λ¦¬ν„΄ν•œλ‹€.
    • 인자둜 μ‚¬μš©λœ λ¦¬μŠ€νŠΈλŠ” μˆ˜μ •ν•˜μ§€ μ•ŠλŠ”λ‹€.

      예제:

      >>> has_duplicates([1, 2, 1, 3])
      True
      >>> has_duplicates(['hello', 'hi', 'hey'])
      False
      

      힌트: 집합(set) μžλ£Œν˜• ν™œμš©

  2. κΈ°λ³Έ μžλ£Œν˜•: νŒŒμΌμ—μ„œ 닀룬 words.txt νŒŒμΌμ„ λ‹€μ‹œ μ΄μš©ν•œλ‹€. words.txt 파일의 λ‚΄μš©μ„ 리슀트 μžλ£Œν˜•μœΌλ‘œ μ €μž₯ν•˜λΌ. 단, 리슀트의 ν•­λͺ©μ€ 각 쀄에 μžˆλŠ” 단어이닀.

    힌트: for 반볡문 ν™œμš©. λ¦¬μŠ€νŠΈμ— 단어λ₯Ό μΆ”κ°€ν•  λ•Œ append와 strip λ©”μ„œλ“œ ν™œμš©. 정닡은 wordlist.py μ°Έκ³ .

  3. μœ„ λ¬Έμ œμ—μ„œ μƒμ„±λœ λ¦¬μŠ€νŠΈμ— νŠΉμ • 단어가 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” ν•¨μˆ˜λ₯Ό 리슀트 μžλ£Œν˜•μ˜ in μ—°μ‚°μž ν™œμš©ν•˜μ—¬ κ΅¬ν˜„ν•˜λΌ.

  4. μœ„ λ¬Έμ œμ—μ„œ κ΅¬ν˜„λœ ν•¨μˆ˜λ₯Ό 이진탐색(binary search)을 μ΄μš©ν•˜λŠ” λ°©μ‹μœΌλ‘œ μˆ˜μ •ν•˜μ—¬ μƒˆλ‘œ κ΅¬ν˜„ν•˜λΌ. 두 ν•¨μˆ˜μ˜ μ‹€ν–‰μ†λ„μ˜ 차이λ₯Ό λΉ„κ΅ν•˜λΌ.
    μ΄μ§„νƒμƒ‰μ˜ κ°œλ…κ³Ό 파이썬 κ΅¬ν˜„μ€ μ΄μ§„νƒμƒ‰ν•˜κΈ°λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€.

    힌트: 정닡은 inlist.py μ°Έκ³ .

  5. κΈ°λ³Έ μžλ£Œν˜•: νŒŒμΌμ—μ„œ 닀룬 words.txt νŒŒμΌμ„ λ‹€μ‹œ μ΄μš©ν•œλ‹€. words.txt 파일의 λ‚΄μš©μ„ 사전 μžλ£Œν˜•μœΌλ‘œ μ €μž₯ν•œ 후에, μƒμ„±λœ 사전에 νŠΉμ • 단어가 ν‚€λ‘œ μ‚¬μš©λ˜μ—ˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” ν•¨μˆ˜λ₯Ό 사전 μžλ£Œν˜•μ˜ in μ—°μ‚°μž ν™œμš©ν•˜μ—¬ κ΅¬ν˜„ν•˜λΌ.

    힌트: words.txt νŒŒμΌμ—μ„œ 단어λ₯Ό 읽어 듀인 ν›„ 각각의 단어λ₯Ό ν‚€λ‘œ μ‚¬μš©ν•œλ‹€. λͺ¨λ“  ν‚€μ˜ 값은 True둜 μ •ν•œλ‹€.

    μ•žμ„œ 리슀트λ₯Ό ν™œμš©ν•œ κ΅¬ν˜„ 방식과 λΉ„κ΅ν•˜μ—¬ 사전 μžλ£Œν˜•μ„ μ΄μš©ν•œ in μ—°μ‚°μžμ˜ 싀행속도가 μ–Όλ§ˆλ‚˜ λΉ λ₯Έμ§€ ν™•μΈν•˜λΌ.

  6. μ–‘μ˜ μ •μˆ˜ n의 νŒ©ν† λ¦¬μ–Ό 값은 1λΆ€ν„° nκΉŒμ§€μ˜ κ³±μ…ˆμ΄λ‹€.

    n! = n*(n-1)*(n-2)*...*2*1

    1. n!을 κ³„μ‚°ν•˜λŠ” ν•¨μˆ˜ factorial을 μ•„λž˜μ™€ 같이 μž¬κ·€λ‘œ κ΅¬ν˜„ν•  수 μžˆλ‹€.

      def factorial(n):
           if n == 1:
               return 1
           else:
               res = n * factorial(n-1)
               return res
      

      계산가λŠ₯ν•œ νŒ©ν† λ¦¬μ–Όμ˜ ν•œκ³„λ₯Ό ν™•μΈν•˜λΌ.

    2. νŒ©ν† λ¦¬μ–Ό ν•¨μˆ˜ factorialDynamicλ₯Ό λ™μ κ³„νšμ„ μ΄μš©ν•˜μ—¬ κ΅¬ν˜„ν•œ 후에, 계산가λŠ₯ν•œ νŒ©ν† λ¦¬μ–Όμ˜ ν•œκ³„κ°€ λ‹¬λΌμ§€λŠ”μ§€ ν™•μΈν•˜λΌ.