16. 사전과 집합#

두 개의 비순차 자료형 사전과 집합을 소개한다. 비순차 자료형은 문자열, 리스트, 튜플과는 달리 순서를 따지지 않으며 항목의 중복도 허용하지 않는다. 사전은 프로그래밍언어에 따라 연관배열, 맵 등으로 불리기도 하며 매우 다양하게 활용된다. 집합과 사전은 해시 가능한 값만을 이용하기에 해시 가능성도 함께 소개한다. 이후에는 논리식을 이용하여 간편하게 리스트와 정의하는 조건제시법을 다룬다.

16.1. 사전#

사전 자료형은 keyvalue의 쌍으로 구성된 항목들의 집합이며, 딕셔너리dictionary 라고도 불린다. 예를 들어, 'Hello''World' 를 키로, '안녕', '세계' 를 각각의 키에 대한 값으로 갖는 사전은 다음과 같다.

{'Hello':'안녕', 'World':'세계'}

빈 사전

빈 사전은 아무것도 포함하지 않는 사전을 의미한다. 빈 사전를 만드는 방법은 아래와 같다.

empty_dict = {}
empty_dict
{}

다음 방식도 가능하다.

empty_dict = dict()
empty_dict
{}

dict() 함수

키-값의 튜플 형식의 항목을 갖는 모음 자료형을 사전으로 변환한다. 단, 키로 사용되는 값은 해시 가능해야 한다.

data = [('Hello', '안녕'), ('World', '세계'), ('Programming', '프로그래밍')]
dict(data)
{'Hello': '안녕', 'World': '세계', 'Programming': '프로그래밍'}

zip() 함수를 활용하면 편리하다.

data = zip('abcde', [1, 2, 3, 4, 5])
data_dict = dict(data)
data_dict
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

사전과 반복문

사전에 대한 반복문은 키key에 대해 실행된다.

for item in data_dict:
    print(item, end=' ')
a b c d e 

키와 값의 쌍에 대해 반복문을 실행하려면 items() 메서드를 이용한다. 단, 키와 값 각각에 대해 변수를 지정하는 게 좋다.

for key, value in data_dict.items():
    print(f"{key:>8} 키의 값: {value}")
       a 키의 값: 1
       b 키의 값: 2
       c 키의 값: 3
       d 키의 값: 4
       e 키의 값: 5

항목을 쪼개서 사용할 수도 있다.

for item in data_dict.items():
    key = item[0]
    value = item[1]
    print(f"{key:>8} 키의 값: {value}")
       a 키의 값: 1
       b 키의 값: 2
       c 키의 값: 3
       d 키의 값: 4
       e 키의 값: 5

값에 대해 반복문을 실행하려면 values() 메서드를 이용한다.

for item in data_dict.values():
    print(item, end=' ')
1 2 3 4 5 

in 연산자

사전의 키로 사용되었는 여부를 알려주는 논리 연산자다.

'city' in {"name": "강현", "age": "3"} 
False

in의 부정은 not in을 사용한다. 즉 키로 사용되지 않았는지 여부를 뭍는다.

'city' not in {"name": "강현", "age": "3"} 
True

len() 함수

사전에 포함된 항목의 개수를 반환한다.

len({"name": "강현", "age": "3"}) 
2

16.1.1. 사전 키 인덱싱#

사전에 사용된 키를 이용한 인덱싱이 지원된다. 예를 들어, 아래 딕셔너리 dic에서 'Hello'에 대응하는 값을 확인하고자 하면
다음과 같이 대괄호를 사용하는 인덱싱을 이용한다.

dic = {'Hello' : '안녕', 'World' : '세계'}
dic['Hello']
'안녕'

존재하지 않는 키로 값을 추출하려고 하면, 오류가 발생한다.

dic['Python']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[13], line 1
----> 1 dic['Python']

KeyError: 'Python'

16.1.2. 항목 추가, 업데이트, 삭제#

아래와 같은 형식으로 사전에 항목을 추가하거나 업데이트 한다.

사전[key] = value

예를 들어, dicPython : 파이썬 항목을 다음과 같이 추가할 수 있다.

dic['Python'] = '파이썬'

dic
{'Hello': '안녕', 'World': '세계', 'Python': '파이썬'}

이미 사용된 키를 이용하면 키와 연결된 값이 업데이트 된다.

dic['World'] = '세상'
dic
{'Hello': '안녕', 'World': '세상', 'Python': '파이썬'}

사전의 항목은 del 명령어에 키를 지정하여 삭제한다.

del dic['World']
dic
{'Hello': '안녕', 'Python': '파이썬'}

16.1.3. 사전 메서드#

사전 자료형이 제공하는 주요 메서드는 아래와 같다.

Table 16.1 사전 주요 메서드#

기능

메서드

설명

키 확인

keys()

사전에 사용된 키로 구성된 순차 자료형 값 반환

값 확인

values()

사전에 사용된 값으로 구성된 순차 자료형 값 반환

키와 값 확인

items()

사전에 사용된 키와 값의 순서쌍으로 구성된 순차 자료형 값 반환

값 반환

get()

지정된 키에 대한 값 반환

dic = {'Hello' : '안녕', 'World' : '세계'}

keys() 메서드: 키로 이루어진 모음 자료형 반환

dic.keys()
dict_keys(['Hello', 'World'])

values() 메서드: 값으로 이루어진 모음 자료형 반환

dic.values()
dict_values(['안녕', '세계'])

items() 메서드: (키, 값) 모양의 쌍으로 이루어진 모음 자료형 반환

dic.items()
dict_items([('Hello', '안녕'), ('World', '세계')])

get() 메서드: 지정된 키와 연관된 값 반환

dic.get('Hello')
'안녕'

존재하지 않는 키를 사용하면 기본값으로 None이 사용된다.

dic.get('hello')

키가 사용되지 않았을 때 기본값을 바꾸려면 둘째 인자를 지정한다.

dic.get('hello', "해당 키가 없어요.")
'해당 키가 없어요.'

예제

6명 정보를 이용하여 키는 이름, 값은 해당 이름의 정보를 담은 리스트를 사용하는 사전을 가리키는 info_dict 변수를 선언하라.

info_list = [['김강현', '010-1234-5678', 20, 172.5, '제주'],
             ['황현', '02-9871-1234', 19, 163.5, '서울'],
             ['남궁수현', '01-3456-7891', 21, 156.7, '경기'],
             ['최흥선', '070-4321-1111', 21, 187.2, '부산'],
             ['김선주', '010-3333-8888', 22, 164.6, '광주'],
             ['함중아', '010-7654-2345', 18, 178.3, '강원']]

답:

6명 각자의 이름을 키로, 나머지 정보로 구성된 리스트를 값으로 사용하는 사전을 구성한다. 이를 위해 for 반복문과 15.4절의 리스트 해체를 이용한다. 먼저 info_list의 항목은 아래 형식임에 주의한다.

person = ['김강현', '010-1234-5678', 20, 172.5, '제주']

위 리스트를 이름과 나머지로 구분하기 위해 다음과 같이 리스트 해체를 이용한다.

name, *rest = person

그러면 name은 이름을, rest는 나머지 항목으로 구성된 리스트를 가리키게 되어 두 변수를 다음과 같이 선언한 것과 동일하다.

name = person[0]
rest = person[1:]

위 설명을 정리해서 info_dict 변수를 아래와 같이 선언한다.

info_dict = dict()

for person in info_list:
    name, *rest = person
    info_dict[name] = rest
info_dict    
{'김강현': ['010-1234-5678', 20, 172.5, '제주'],
 '황현': ['02-9871-1234', 19, 163.5, '서울'],
 '남궁수현': ['01-3456-7891', 21, 156.7, '경기'],
 '최흥선': ['070-4321-1111', 21, 187.2, '부산'],
 '김선주': ['010-3333-8888', 22, 164.6, '광주'],
 '함중아': ['010-7654-2345', 18, 178.3, '강원']}

예를 들어 김선주의 정보를 보고 싶으면 다음과 같이 실행한다.

info_dict['김선주']
['010-3333-8888', 22, 164.6, '광주']

예제

이름을 물으면 나이를 확인해주는 name_age() 함수를 선언하라. 단, 이름이 없으면 “정보 없음”을 반환해야 한다.

힌트: get() 사전 메서드 활용

답:

앞서 선언한 info_dict 변수를 활용할 수 있다. 이유는 이름을 사용하여 인덱싱을 적용하면 전화번호, 나이, 키, 출생지 정보로 구성된 리스트가 확인된다. 따라서 인덱싱으로 쉽게 나이를 확인할 수 있다.

그런데 키 인덱싱을 활용할 때 키가 사용되지 않았다면 오류가 발생한다. 따라서 try-except 명령문을 이용하여 다음과 같이 name_age() 함수를 구현할 수 있다.

def name_age(name):
    try:
        info = info_dict[name]
        return info[1]
    except KeyError:
        return "정보없음"

반면에 get() 메서드를 활용하면 오류 없이 코드가 실행된다. 다면 반환값이 None인지 여부를 구분해야 한다.

def name_age(name):
    info = info_dict.get(name)
    # info가 None이 아닌지 여부 판단
    if info:
        return info[1]
    else:
        return "정보없음"

16.2. 집합#

집합 자료형은 수학에서 다루는 집합처럼 작동하도록 만든 비순차 모음 자료형이며 다음과 같이 중괄호를 사용하여 정의된다. 집합은 항목의 중복을 허용하지 않고, 항목들 사이의 순서 또한 무시된다. 따라서 인덱싱이나 슬라이싱을 지원하지 않는다.

{항목1, 항목2, 항목3, ..., 항목n}

a_set = {4, 4, 9.2, "apple", True, 4}
a_set
{4, 9.2, True, 'apple'}

공집합

공집합empty set은 아무것도 포함하지 않는 집합을 의미한다. 공집합를 만드는 방법은 아래와 같다.

empty_set = set()
empty_set
set()

{}은 빈 사전을 가리킴에 주의한다.

a = {}
type(a)
dict

set() 함수

임의의 모음 자료형을 집합으로 변환한다. 이 과정에서 순서와 중복이 무시된다.

set([5, 1, 1, 2, 5, 5, 1])
{1, 2, 5}
set((1, 3, 3, 9, 1))
{1, 3, 9}

순차 자료형의 항목에서 중복을 제거하고 싶을 때 set() 함수가 유용하게 활용된다. 예를 들어 아래 코드는 리스트에서 중복된 항목이 삭제된, 하지만 동일한 항목을 포함한 새로운 리스트를 생성한다. 단, 기존 리스트에서 사용된 항목들의 순서는 보존되지 않음에 주의한다.

list(set([5, 1, 1, 2, 5, 5, 1]))
[1, 2, 5]

in 연산자

집합의 항목(원소)으로 등장하는지 여부를 알려주는 논리 연산자다.

1 in {1, 2, 3, 9, 4}
True
'a' not in {1, 'b', True, 9}
True

len() 함수

집합에 포함된 항목의 개수를 반환한다.

len({1, 3, 5, 7, 9})
5

16.2.1. 집합 메서드#

집합 자료형이 제공하는 주요 메서드는 아래와 같다.

Table 16.2 사전 주요 메서드#

기능

메서드

설명

합집합

union()

A.union(B): A \(\cup\) B 반환

교집합

intersection()

A.intersection(B): A \(\cap\) B 반환

차집합

difference()

A.difference(B): A - B, 즉, A에만 포함된 항목들의 집합 반환

부분집합 여부

issubset()

A.issubset(B): AB의 부분집합일 때 True 반환

항목 추가

add()

A.add(c): 집합 A에 항목 c 추가. 반환값 None

학목 삭제

remove()

A.remove(c): 집합 A에서 항목 c 삭제. 반환값 None

여기서는 집합 메서드를 자세히 다루지 않는다. 이유는 각각의 메서드의 기능이 중, 고등학교에서 배운 집합 연산과 동일하기 때문이다.

  • 합집합 생성

A = {1, 2, 3}
B = {2, 4}
A.union(B)
{1, 2, 3, 4}
  • 교집합 생성

A.intersection(B)
{2}
  • 차집합 생성

A.difference(B)
{1, 3}
  • 부분집합 여부 확인

A.issubset(B)
False
A.issubset(A.union(B))
True
  • 항목(원소) 추가

A.add(5)
A
{1, 2, 3, 5}
  • 항목(원소) 삭제

A.remove(5)
A
{1, 2, 3}

여기서는 아래 예제를 이용하여 중복을 없애는 set() 함수의 유용성을 소개한다.

예제

info_dict를 이용하여 키는 나이, 값은 해당 나이를 갖는 사람의 수를 사용하는 사전을 가리키는 age_count_dict를 선언하라.

답:

info_dict는 다음과 같다.

info_dict
{'김강현': ['010-1234-5678', 20, 172.5, '제주'],
 '황현': ['02-9871-1234', 19, 163.5, '서울'],
 '남궁수현': ['01-3456-7891', 21, 156.7, '경기'],
 '최흥선': ['070-4321-1111', 21, 187.2, '부산'],
 '김선주': ['010-3333-8888', 22, 164.6, '광주'],
 '함중아': ['010-7654-2345', 18, 178.3, '강원']}

먼저 나이로 구성된 리스트를 생성한다.

ages = []

for person in info_list:
    ages.append(person[2])
    
print(ages)
[20, 19, 21, 21, 22, 18]

리스트에 포함된 나이를 확인하기 위해 중복을 제거한다. 이를 위해 집합 자료형으로 변환시킨다.

ages_set = set(ages)
ages_set
{18, 19, 20, 21, 22}

ages_set 집합에 포함된 각각의 항목을 대상으로 count() 리스트 메서드를 적용하면 원하는 사전을 생성할 수 있다.

age_count_dict = dict()

for age in ages_set:
    age_count_dict[age] = ages.count(age)
age_count_dict
{18: 1, 19: 1, 20: 1, 21: 2, 22: 1}

16.2.2. 해시 가능성#

집합의 항목으로 리스트, 사전, 집합과 같은 가변 자료형은 사용할 수 없다.

{[1, 3], 4}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[58], line 1
----> 1 {[1, 3], 4}

TypeError: unhashable type: 'list'

사전의 키 또한 리스트를 키로 사용할 수 없다.

no_list_keys = {[1, 2]: "리스트는 키로 사용할 수 없음"}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[59], line 1
----> 1 no_list_keys = {[1, 2]: "리스트는 키로 사용할 수 없음"}

TypeError: unhashable type: 'list'

이유는 리스트 등의 가변 자료형은 해시 가능하지 않기 때문이다.

hash() 함수

파이썬 객체의 해시 가능성은 hash() 함수의 인자로 사용될 수 있는가에 의해 결정된다. 즉 hash() 함수와 함께 호출됐을 때 오류가 발생하지 않아야 한다. 이렇게 hash() 함수와 함께 호출되었을 때 오류가 발생하지 않은 값을 해시 가능hashable하다고 부른다.

해시 가능한 값에 대해 hash() 함수의 반환값은 특정 정수이며 서로 다른 두 값은 서로 다른 반환값을 갖는다. 즉, 조금이라도 다른 해시 가능한 값이 인자로 지정되면 다른 값을 계산한다.

hash('123')
-6307178578295685641
hash('123 ')
3543337771683958828
hash((1, 3, 4))
-1070212610609621906
hash((1, 2, 4))
-4363729961677198915

해시 함수의 반환값

hash() 함수의 반환값이 실행할 때마다 달라질 수 있다. 이는 보안상의 이유로 무작위 기능이 적용되기 때문이다. 항상 고정된 값을 반환하는 해시 함수도 있지만 여기서는 다루지 않는다.

반면에 리스트 등 가변 자료형의 객체는 해시 가능하지 않다.

hash([1, 3])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[64], line 1
----> 1 hash([1, 3])

TypeError: unhashable type: 'list'

리스트를 포함한 튜플도 해시 가능하지 않다.

hash(([1, 2], 3))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[65], line 1
----> 1 hash(([1, 2], 3))

TypeError: unhashable type: 'list'

집합에 해시 가능한 값만 포함될 수 있는 이유는 두 항목을 구별하기 위해 hash() 함수를 이용하기 때문이다. 반면에 리스트 등과 같은 가변 자료형의 값은 언제든 변할 수 있기에 정체를 제대로 파악할 수 없다.

16.3. 조건제시법#

조건제시법comprehension을 이용하여 리스트, 집합, 사전을 정의할 수 있다.

리스트 조건제시법

수학에서 0과 10사이에 있는 홀수들의 제곱을 원소로 갖는 집합을 조건제시법으로 표현하면 다음과 같다.

\[\{ x^2 \mid 0 \le x \le 10, \text{ 단 $x$는 홀수} \}\]

0과 10 사이에 있는 홀수들의 제곱을 항목으로 갖는 리스트를 for 반복문으로 구현해 보자.

zero2ten_odd = []

for x in range(11):
    if x%2 == 1:
        zero2ten_odd.append(x**2)

zero2ten_odd
[1, 9, 25, 49, 81]

조건제시법을 이용하여 보다 간단하게 리스트를 생성할 수 있다.

zero2ten_odd = [x**2 for x in range(11) if x%2 == 1]
zero2ten_odd
[1, 9, 25, 49, 81]

위 두 코드를 비교하면 조건제시법의 작동원리를 이해할 수 있을 것이다.

집합 조건제시법

위 결과를 집합으로 구현하면 다음과 같다.

zero2ten_odd_set = {x**2 for x in range(11) if x%2 == 1}
zero2ten_odd_set
{1, 9, 25, 49, 81}

사전 조건제시법

조건제시법을 이용하여 사전을 생성하는 과정도 유사하다. 아래 코드는 0부터 10 사이의 홀수를 키로, 홀수의 제곱은 값으로 갖는 항목으로 구성된 사전을 생성한다.

odd_squares = {x : x**2 for x in range(11) if x%2 == 1}
odd_squares
{1: 1, 3: 9, 5: 25, 7: 49, 9: 81}

반면에 아래 코드는 문장에 포함된 단어를 키로, 단어의 길이를 값으로 갖는 항목들로 구성된 사전을 생성한다.

words = '파이썬은 범용 프로그래밍 언어입니다.'.split()
print(words)
['파이썬은', '범용', '프로그래밍', '언어입니다.']
len_dict = {k : len(k) for k in words}
len_dict
{'파이썬은': 4, '범용': 2, '프로그래밍': 5, '언어입니다.': 6}

16.4. 예제#

예제 1

아래 코드 중 오류가 발생하는 코드를 예측하여 말하고, 코드를 실행시켜 확인하여라.

(1)

dic1 = { 1 : 'a'}
dic1
{1: 'a'}

답:

사전의 키는 해시 가능해야 하는데, 정수는 해시 가능하다.

hash(1)
1

(2)

dic3 = {'abc' : 'a'}
dic3
{'abc': 'a'}

답:

사전의 키는 해시 가능해야 하는데, 문자열 해시 가능하다.

hash('abc')
-2898649570265123009

(3)

dic4 = {[1, 2] : 'a'}
dic4
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 dic4 = {[1, 2] : 'a'}
      2 dic4

TypeError: unhashable type: 'list'

답:

사전의 키는 해시 가능해야 하는데, 리스트는 해시 가능하지 않다.

hash([1, 2])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 hash([1, 2])

TypeError: unhashable type: 'list'

예제 2

영어 단어는 키로, 단어의 뜻은 값으로 하는 사전이 다음과 같이 주어졌다.

eng_dict = {'dog': '개', 'cat': '고양이', 'lion': '사자', 'tiger': '호랑이', 'snake': '뱀'}

영어 단어가 인자로 입력되었을 때 사전의 키로 사용되었다면 뜻을 반환하고, 아니면 아래 문장을 반환하는 eng_fun() 함수를 선언하라. 단, 대소문자는 구분하지 않는다.

찾는 단어가 없습니다.

답:

사전에 키로 사용된 영어 단어는 모두 소문자만 사용한다. 따라서 입력값을 먼저 소문자만 사용하도록 한 다음에 키로 사용되었는지 여부를 판단한다.

def eng_fun(word):
    word = word.lower()
    if word in eng_dict:
        return eng_dict[word]
    else:
        return '찾는 단어가 없습니다.'
eng_fun('dog')
'개'
eng_fun('fox')
'찾는 단어가 없습니다.'

다음과 같이 사전의 get() 메서드를 이용하여 eng_func() 함수를 선언할 수도 있다.

def eng_fun(word):
    word = word.lower()
    return eng_dict.get(word, '찾는 단어가 없어요.')
eng_fun('dog')
'개'
eng_fun('fox')
'찾는 단어가 없어요.'

반면에 다음과 같이 사전 인덱싱을 이용하면 찾는 단어가 없는 경우 오류가 발생한다.

def eng_fun(word):
    word = word.lower()
    return eng_dict[word]
eng_fun('dog')
'개'
eng_fun('fox')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[16], line 1
----> 1 eng_fun('fox')

Cell In[14], line 3, in eng_fun(word)
      1 def eng_fun(word):
      2     word = word.lower()
----> 3     return eng_dict[word]

KeyError: 'fox'

다음과 같이 예외처리를 이용할 수는 있다.

def eng_fun(word):
    word = word.lower()
    try:
        return eng_dict[word]
    except:
        return "찾는 단어가 없어요."   
eng_fun('dog')
'개'
eng_fun('fox')
'찾는 단어가 없어요.'

하지만 예외처리를 하는 것보다는 get() 메서드를 사용하여 애초에 오류가 발생하지 않도록 코드를 작성하는 게 보다 중요하다.

예제 3

정수들의 리스트가 인자로 입력되었을 때 리스트의 항목은 키로, 해당 항목이 위치한 곳의 인덱스들의 리스트를 값으로 갖는 사전 객체를 반환하는 list2dic() 함수를 구현하라.

list2dic() 함수는 예를 들어 아래와 같이 작동해야 한다.

list2dic([2, 5, 2, 3, 3, 2]) = {2: [0, 2, 5], 3: [3, 4], 5: [1]}
list2dic([15, 3, 15, 1, 3, 8]) = {1: [3], 3: [1, 4], 8: [5], 15: [0, 2]}

힌트: enumerate() 함수, 리스트의 count() 메서드, collections 모듈의 defaultdict 클래스를 이용한다.

답 1:

def list2dic(xs):
    list_dict = dict()
    for i, item in enumerate(xs):
        if item in list_dict:
            list_dict[item].append(i)
        else:
            list_dict[item] = [i]

    return list_dict
print(list2dic([2, 5, 2, 3, 3, 2]))
print(list2dic([15, 3, 15, 1, 3, 8]))
{2: [0, 2, 5], 5: [1], 3: [3, 4]}
{15: [0, 2], 3: [1, 4], 1: [3], 8: [5]}

답 2:

collections 모듈의 defaulitdict를 활용하면 보다 간단하게 함수를 구현할 수 있다.

from collections import defaultdict
list_dict = defaultdict(list)
list_dict
defaultdict(list, {})
list_dict[1].append(3)
list_dict[2].append(0)
list_dict
defaultdict(list, {1: [3], 2: [0]})
def list2dic(xs):
    list_dict = defaultdict(list)
    for i, item in enumerate(xs):
        list_dict[item].append(i)

    return dict(list_dict)
print(list2dic([2, 5, 2, 3, 3, 2]))
print(list2dic([15, 3, 15, 1, 3, 8]))
{2: [0, 2, 5], 5: [1], 3: [3, 4]}
{15: [0, 2], 3: [1, 4], 1: [3], 8: [5]}

예제 4

(1) 아래 리스트를 리스트 조건제시법으로 정의하라.

[3, 6, 9, 12, 15]

답:

multiples_3 = [ 3*x for x in range(1,6) ]
print(multiples_3)
[3, 6, 9, 12, 15]

또는

multiples_3 = [ x for x in range(1,16) if x % 3 == 0]
print(multiples_3)
[3, 6, 9, 12, 15]

(2) 0부터 20까지의 자연수 중에서 3으로 나눈 나머지가 2이면서 짝수인 수의 제곱으로 이루어진 리스트를 조건제시법으로 정의하라. 즉, 아래 리스트를 조건제시법으로 생성해야 한다.

[4, 64, 196, 400]

답:

list_modulo3 = [x**2 for x in range(0, 21) if x%3 == 2 and x%2 == 0]

print(list_modulo3)
[4, 64, 196, 400]

예제 5

6명의 정보가 다음과 같다.

kgh = ['김강현', '010-1234-5678', 20, 172.3, '제주']
whang = ['황현', '02-9871-1234', 19, 163.5, '서울']
namgung = ['남세원', '010-3456-7891', 21, 156.7, '경기']
choihs = ['최흥선', '070-4321-1111', 21, 187.2, '부산']
sjkim = ['김현선', '010-3333-8888', 22, 164.6, '광주']
ja = ['함중아', '010-7654-2345', 18, 178.3, '강원']
info_list = [kgh, whang, namgung, choihs, sjkim, ja]
info_list
[['김강현', '010-1234-5678', 20, 172.3, '제주'],
 ['황현', '02-9871-1234', 19, 163.5, '서울'],
 ['남세원', '010-3456-7891', 21, 156.7, '경기'],
 ['최흥선', '070-4321-1111', 21, 187.2, '부산'],
 ['김현선', '010-3333-8888', 22, 164.6, '광주'],
 ['함중아', '010-7654-2345', 18, 178.3, '강원']]

(1) info_list에 포함된 6명의 이름과 전화번호만으로 구성된 사전을 가리키는 phone_dict 변수를 for 반복문을 이용하여 선언하라. 단, 키는 이름, 값은 전화번호로 지정하며, 조건제시법은 사용하지 않는다.

답:

phone_dict = dict()

for people in info_list:
    name = people[0]
    phone_number = people[1]
    phone_dict[name] = phone_number
phone_dict    
{'김강현': '010-1234-5678',
 '황현': '02-9871-1234',
 '남세원': '010-3456-7891',
 '최흥선': '070-4321-1111',
 '김현선': '010-3333-8888',
 '함중아': '010-7654-2345'}

(2) phone_dict 변수가 가리키는 값을 조건제시법을 이용하여 선언하라.

답:

phone_dict = {people[0]:people[1] for people in info_list}
phone_dict
{'김강현': '010-1234-5678',
 '황현': '02-9871-1234',
 '남세원': '010-3456-7891',
 '최흥선': '070-4321-1111',
 '김현선': '010-3333-8888',
 '함중아': '010-7654-2345'}

(3) phone_dict를 이용해서 이름을 지정하면 전화번호를 알려주는 phone_book() 함수를 정의하라.

def phone_book(name):
    return phone_dict[name]
phone_book('김현선')
'010-3333-8888'
phone_book('최흥선')
'070-4321-1111'

예제 6

아래 문자열을 이용한다.

lyrics = "Twinkle, twinkle, little star. How I wonder what you are."

(1) 위 문자열을 소문자로 변경한 후, 공백을 기준으로 쪼개진 단어들의 리스트를 lyrics_list 변수에 할당하라.

lyrics_list = lyrics.lower().split()
lyrics_list
['twinkle,',
 'twinkle,',
 'little',
 'star.',
 'how',
 'i',
 'wonder',
 'what',
 'you',
 'are.']

(2) lyrics_list의 각 항목의 문자열 길이를 항목으로 갖는 리스트를 만들어라.
예를 들어, ['hello', 'python']의 경우, 각 항목의 문자열 길이를 항목으로 갖는 리스트는 [5, 6] 이다.

[len(x) for x in lyrics_list]
[8, 8, 6, 5, 3, 1, 6, 4, 3, 4]

(3) lyrics_list의 항목 중 일부는 콤마(,)나 마침표(.)가 사용되었다. 콤마나 마침표를 제외한 단어의 길이를 표시하도록 (2)의 코드를 수정하여라.

[len(x.strip('.').strip(',')) for x in lyrics_list]
[7, 7, 6, 4, 3, 1, 6, 4, 3, 3]

예제 7

리스트를 인자로 받아서 사용된 항목의 개수를 반환하는 함수 count_elem()를 구현하라. 단, 중복 항목은 하나로 간주한다.

count_elem([2, 5, 2, 3, 3, 8, 2, 7]) = 5
count_elem([15, 3, 15, 1, 3]) = 3

답:

def count_elem(xs):
    return len(set(xs))

print(count_elem([2, 5, 2, 3, 3, 8, 2, 7]))
print(count_elem([15, 3, 15, 1, 3]))
5
3

예제 8

교육 참가자 명단과 수료자 명단이 아래처럼 리스트로 주어다.

participant = ['Apeach', 'Ryan', 'Muzi', 'Choonsik', 'Neo', 'Tube']
completion = ['Ryan', 'Muzi', 'Neo', 'Choonsik']

수료하지 못한 사람들의 명단을 리스트로 출력하는 코드를 작성하여라. 단, 참여자 중 동명이인은 없고, 순서는 중요하지 않다.

답:

unfinished = list(set(participant) - set(completion))
unfinished
['Apeach', 'Tube']

또는

unfinished = list(set(participant).difference(set(completion)))
unfinished
['Apeach', 'Tube']

16.5. 연습문제#

참고: (연습) 사전과 집합