4. 자료구조

 4. 자료구조


4-1. 리스트


리스트 ([]) : 순서를 가지는 객체의 집합 


subway = [10, 20, 30]

print(subway) 


<실행결과>

[10, 20, 30]





* 컴프리헨션

for문을 이용하여 순차적인 리스트를 생성할 때 한 줄로 간단하게 만들 수 있다. 


- 일반적인 방법

numlst = []
for num in range(1, 6):
    numlst.append(num)

print(numlst)

<실행결과>

[1, 2, 3, 4, 5]


- 컴프리헨션 방식

numlst = [num for num in range(1, 6)]

print(numlst)

<실행결과>

[1, 2, 3, 4, 5]



- 컴프리헨션의 구성 

(리스트) = [(수식) for (항목) in range() if (조건식)]

수식과 조건식을 이용해서 더 복잡한 구성의 리스트도 한 줄로 생성할 수 있다.

(리스트) = [ (참일때) if (조건) else (거짓일때) for (항목) in range() ]



예) 1~5의 제곱 중 홀수로만 이루어진 리스트 생성

numlst = [num**2 for num in range(1, 6) if (num**2) % 2 == 1]

print(numlst)

<실행결과>

[1, 9, 25]


예) 음수면 0 양수면 그대로 저장

arr = [-1, 0, -4, 24, 5, -10, 2]
numlst = [i if i > 0 else 0 for i in arr]

print(numlst)

<실행결과>

[0, 0, 0, 24, 5, 0, 2]



- 중첩 for문 

[리스트] = [ (수식) for (항목1) in range for (항목2) in range ]

예) 중첩 for 문 활용

일반 방식

numlst = []
for i in range(1, 4):
    for j in range(1,3):
        numlst.append(i * j)

print(numlst)

컴프리헨션 방식

numlst = [i * j for i in range(1, 4) for j in range(1, 3)]

print(numlst)

<실행결과>

[1, 2, 2, 4, 3, 6]



- 중첩 리스트

[리스트] = [ [ 수식 for  (항목) in range()] for (항목) in range() ] 

예) 중첩 리스트 생성

numlst = [[i for i in range(3)] for j in range(2)]

print(numlst)

<실행결과>

[[0, 1, 2], [0, 1, 2]]





* 리스트 요소로 접근

[] 안에 index를 입력해서 접근

0~ : 앞에서 부터

-1 ~ (작아짐) : 뒤에서 부터


: 을 이용해서 범위로 접근 가능


예 )

lst = [1, 2, 3, 4, 5]
print(lst[0], lst[1])
print(lst[-1], lst[-2])
print(lst[1:3])
print(lst[:2]) 

<실행결과>

1 2

5 4

[2, 3]

[1, 2]


:: 을 이용해서 값을 건너뛰며 접근 가능

[::2] : 앞에서부터 2개씩 건너뜀

[::-2 : 뒤에서부터 2개씩 건너뜀

[::-1] : 뒤에서부터 1개씩 건너뜀 (배열 거꾸로 추출)


예)

lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(lst[::2])
print(lst[::-2])
print(lst[::-1])

<실행결과>

[0, 2, 4, 6, 8]

[9, 7, 5, 3, 1]

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]






*관련 함수들


.append() : 뒤에 다른 항목을 더해줌

subway.append(40) => [10, 20, 30, 40]


.insert() : 지정한 위치에 다른 항목을 더해줌 (추가할 위치(0 부터 시작), 추가할 객체)

subway.insert(2, 50) => [10, 20, 50, 30, 40]


.pop() : 맨 뒤의 객체를 추출 함 (맨 뒤에 항목 반환하고 해당 리스트에서 삭제)

print(subway.pop())

print(subway)

<실행결과>

40

[10, 20, 50, 30]


.count() : ()안의 항목이 몇 개 있는지 세줌

subway.count(10) => 1


.sort() : 정렬

subway.sort() => [10, 20, 30, 50]


.reverse() : 순서 뒤집기

subway.reverse() => [50, 30, 20, 10]


(.sort() 와 .reverse() 는 print 안에서 하면 안되고 print 밖에서 하고 그 다음에 출력을 해야 한다.


.clear() : 리스트 내 모든 항목 지우기 

subway.clear() => []


.extend() : 리스트 확장

a = [1, 2, 3]

b = [4, 5, 6]

a.extend(b) => [1, 2, 3, 4, 5, 6]


*리스트는 자료형에 상관 없이 섞어서 사용이 가능하다.

["python", 98, True, [1, 2, 3]]



* enumerate : 리스트의 index 와 value 를 받아온다.


- 사용예시

lst = ["A", "B", "C"]

for i, j in enumerate(lst):
print(i, j)

<실행결과>

0 A

1 B

2 C




* zip() : 동시에 여러 리스트에 접근하게 해준다.

foods = ['라면', '짜장면', '치킨', '피자', '삼겹살']
sides = ['김치', '단무지', '치킨무']

for food, side in zip(foods, sides):
    print(food, "  ==>  ", side)

<실행결과>

라면   ==>   김치

짜장면   ==>   단무지

치킨   ==>   치킨무


(접근하는 리스트의 크기가 다른 경우 작은 크기의 리스트 기준으로만 반복한다.)




* .remove() : () 안의 내용을 리스트에서 삭제한다. 


-사용예시

lst = [1, 2, 3]

lst.remove(2)

print(lst)


<실행결과>

[1, 3]




* del() : remove()와 비슷하나 ()안에 값이 아닌 리스트[index]를 입력한다.

lst = [1, 2, 3]

del(lst[1])

print(lst)


<실행결과>

[1, 3]




그 외에 리스트의 내용을 삭제하는 방법으로는 해당 리스트 값에 []를 대입하는 방법이 있다.

범위를 지정하면 여러 내용을 한꺼번에 삭제할 수도 있다. 하나만 삭제하더라도 index값이 아닌 범위로 입력해줘야 한다.

lst = [1, 2, 3, 4, 5]

lst[1:2] = []

print(lst)

lst[2:4] = []

print(lst)

<실행결과>

[1, 3, 4, 5]

[1, 3]



리스트 전체를 삭제하는 방법으로는 3가지가 있다.

해당 리스트에 [] 대입하기 : 리스트 형태만 남게 된다.

해당 리스트에 None 대입하기 : 존재는 하나 아무 값도 없게 된다.

해당 리스트를 del() 안에 넣는다 : 해당 리스트를 담고 있는 변수 자체가 사라진다.

lst = [1, 2, 3, 4, 5]
lst = []
print(lst)

lst = [1, 2, 3, 4, 5]
lst = None
print(lst)

lst = [1, 2, 3, 4, 5]
del(lst)
print(lst)

<실행결과>

[]

None

에러 발생 name 'lst' is not defined





* 리스트 수정하기

[] 안에 수정할 index 값을 넣고 수정할 값을 대입

a = [1, 2, 3]

a[1] = 200

print(a)

<실행결과>

[1, 200, 3]


한 개의 값을 여러 개의 값으로 수정할 수도 있다.

a = [1, 2, 3]

a[1] = [200, 300]

print(a)

<실행결과>

[1, [200, 300], 3]


위와 같이 코드를 짜면 리스트 자체가 값으로 들어가게 된다. 리스트가 아닌 값을 넣으려면 [] 안에 index 값이 아닌 범위로 넣으면 된다.

a = [1, 2, 3]

a[1:2] = [200, 300]

print(a)

<실행결과>

[1, 200, 300, 3]




* 리스트 복사하기

파이썬에서 리스트를 복사할 때 그냥 대입 연산자를 사용하면 리스트의 값이 아닌 리스트가 저장된 주소가 대입 된다. 따라서 대입한 후에 기존 리스트를 수정하면 대입한 리스트도 같이 수정되게 된다. 


a = [1, 2, 3]
b = a

a.append(4)

print(a)
print(b)

<실행결과>

[1, 2, 3, 4]

[1, 2, 3, 4]



따라서 이러한 문제를 해결하기 위해 리스트의 값을 복사하는 방법에는 다음과 같이 두 가지가 있다. 

a = [1, 2, 3]
b = a[:] #리스트의 전체 내용을 대입

a.append(4)

c = a.copy() #copy() 함수를 이용한 복사

a.append(5)

print(a)
print(b)
print(c)

<실행결과>

[1, 2, 3, 4, 5]

[1, 2, 3]

[1, 2, 3, 4]



*리스트에서 사용할 수 있는 다양한 함수들



















4-2. 사전


사전({  }) : key 와 value가 짝을 이루는 자료구조이다. (순서가 없음)

{key : value} (key와 value의 자료형이 일치할 필요는 없음)


cabinet = {3: 'boy', 5:'girl'}

print(cabinet[3])

print(cabinet[5])

<실행결과>

boy

girl


또는 .get() 을 사용할 수도 있다.


print(cabinet.get(3))

print(cabinet.get(5))

<실행결과>

boy

girl


*key에 없는 값을 입력하면 []를 사용해 값을 호출한 경우에는 에러가 발생하고

.get()을 사용한 경우에는 None이 출력된다. key 값 뒤에 다른 문구를 입력하면 key값이 없는 경우 그문구가 출력이 된다.


print(cabinet.get(4, "사용 가능한 키"))

<실행결과>

사용가능한 키





빈 사전 생성 - dict()

a = dict()
print(a)

<실행결과>

{}




in : 어떤 자료가 사전에 있는지 없는지 확인해 준다. (key 값)


print(3 in cabinet)

print(4 in cabinet)

<실행결과>

True

False




* 정수가 아닌 문자를 key로 사용할 수도 있다.

ex) {"언어" : "python"}




*사전에 새로운 값을 추가하거나 업데이트 하기 

(기존에 있는 키를 사용하면 값이 추가되지 않고 수정됨)


cabinet[7] = 'man'
cabinet[5] = 'woman'

print(cabinet)

<실행결과>

{3 : 'boy', 5 : 'woman', 7 : 'man'}




del : 값 지우기

del cabinet[3]

print(cabinet)

<실행결과>

{5 : 'woman', 7 : 'man'}




.keys() : 사전 내 모든 key들만 출력

print(cabinet.keys())

<실행결과>

dict_keys([5, 7])



.values() : 사전 내 모든 value들만 출력

print(cabinet.values())

<실행결과>

dict_values(['woman', 'man'])



.items() : 사전 내의 모든 key 와 value 를 출력

print(cabinet.items())

<실행결과>

dict_items([(5 : 'women'), (7 : 'man')])



출력 결과를 깔끔하게 (dict_~~ 를 보기 싫다면 ) 리스트로 감싸서 볼 수 있음

print(list(cabinet.keys()))
print(list(cabinet.values()))
print(list(cabinet.items()))

<실행결과>

[5, 7]

['woman', 'man']

[(5, 'woman'), (7, 'man')]




.clear() : 사전 내의 모든 객체를 다 지움

cabinet.clear()

<실행결과>

{}




for 문을 사용한 딕셔너리의 모든 값 출력

person = {}

person["name"] = "Kim"
person["age"] = 23
person["height"] = 180
person["weight"] = 73

for k in person.keys() :
    print("{} : {}".format(k, person[k]))

<실행결과>

name : Kim

age : 23

height : 180

weight : 73





* 튜플 리스트로 딕셔너리 생성

lst = [("korea", 410), ("china", 156), ("japan", 392)]
dict1 = dict(lst)
print(dict1)

<실행결과>

{'korea': 410, 'china': 156, 'japan': 392}



* 리스트 두 개를 묶어서 딕셔너리 생성 (zip() 함수로 묶어줌)

key = ["korea", "china", "japan", "usa"]
value = [410, 156, 392]
dict2 = dict(zip(key, value))
print(dict2)

<실행결과>

{'korea': 410, 'china': 156, 'japan': 392}

-> 두 리스트의 요소 개수가 다르면 짝이 없는 요소(usa)는 딕셔너리에 추가되지 않음





* operator.itemgetter() - 딕셔너리 정렬

operator 모듈을  import 해서 사용

사전이나 중첩 리스트 정렬을 도와줌

sort() 나 sorted() 함수를 통해서 정렬을 수행할 때 sort()나 sorted() 함수의 key 매개변수(정렬할 기준 설정)에 operator.itemgetter()를 이용해서 정렬할 기준을 설정

() 안에는 기준값의 위치나 직접 key값을 입력

사전에는 sort() 함수가 없으므로 sorted() 함수를 이용


import operator

student = {"jane" : "제인", "dave" : "데이브", "sally" : "셀리"}
studentDic = sorted(student.items(), key=operator.itemgetter(0))
print(studentDic)

<실행결과>

[('dave', '데이브'), ('jane', '제인'), ('sally', '샐리')]

-> 0번째 요소를 기준으로 정렬


itemgetter() 안에 0 대신 1을 넣으면 사전의 두 번째(1번 째)에 있는 한글 이름을 기준으로 정렬을 실행

import operator

student = {"jane" : "제인", "dave" : "데이브", "sally" : "셀리"}
studentDic = sorted(student.items(), key=operator.itemgetter(1))
print(studentDic)

<실행결과>

[('dave', '데이브'), ('sally', '셀리'), ('jane', '제인')]



(사전 뿐만 아니라 중첩 리스트에도 적용이 가능하다.)



itemgetter() 안에 index 뿐만 아니라 직접 값 입력 가능

import operator

students =[
    {"name": "jane", "age": 22, "grade": 'A'},
    {"name": "dave", "age": 32, "grade": 'B'},
    {"name": "sally", "age": 17, "grade": 'B'}
]
students.sort(key=operator.itemgetter('name'))
print(students)

<실행결과>

[{'name': 'dave', 'age': 32, 'grade': 'B'},
{'name': 'jane', 'age': 22, 'grade': 'A'},
{'name': 'sally', 'age': 17, 'grade': 'B'}]

-> 지정한 'name'을 기준으로 정렬 




* setdefault([변경될 key], [변경할 value]) : 딕셔너리에 값을 추가할 때 실수로 값이 변경되는 것을 방지하기 위해 key 값이 존재하는 경우 해당 값을 반환해서 값의 변경을 막음 (없는 key 값이 입력되면 새로운 값 추가)

color = {"red" : "빨강", "green" : "초록", "blue" : "파랑"}

color.setdefault("red", "래드") # 변경 안됨
color.setdefault("yellow", "노랑") # 값 추가
print(color)

<실행결과>

{'red': '빨강', 'green': '초록', 'blue': '파랑', 'yellow': '노랑'}





* update([결합할 딕셔너리])

두 딕셔너리를 결합

rgb = {"red" : "빨강", "green" : "초록", "blue" : "파랑"}
cmy = {"cyan" : "하늘", "magenta" : "자주", "yellow" : "노랑"}

rgb.update(cmy)
print(rgb)

<실행결과>

{'red': '빨강', 'green': '초록', 'blue': '파랑', 'cyan': '하늘', 'magenta': '자주', 'yellow': '노랑'}


이미 있는 key 에 대해서는 뒤의 요소로 변경

rgb = {"red" : "빨강", "green" : "초록", "blue" : "파랑"}
cmy = {"cyan" : "하늘", "red" : "레드", "yellow" : "노랑"}

rgb.update(cmy)
print(rgb)

<실행결과>

{'red': '레드', 'green': '초록', 'blue': '파랑', 'cyan': '하늘', 'yellow': '노랑'}

-> 'red' 가 '빨강' 에서 '레드' 로 변경됨








4-3. 튜플


튜플 (()) : 리스트와 다르게 내용변경 및 추가가 안되지만 리스트 보다 속도가 더 빠르다.


menu = ('떡볶이', '튀김', '순대')

print(menu[0])
print(menu[1])
print(menu[2])

<실행결과>

떡볶이

튀김

순대



항목이 하나인 경우 그냥 괄호 안에 값만 넣으면 일반 변수로 선언되기 때문에 원소가 하나 이더라도 반드시 뒤에 쉼표를 찍어줘야 함

t1 = (1)
t2 = (2,)

print(t1)
print(t2)

<실행결과>

1

(2,)






name = 'Tom'
age = 21
hobby = 'game'

print(name, age, hobby)

<실행결과>

Tom 21 game


위 코드를 튜플을 이용하면 더 간단하게 쓸 수 있다.


(name, age, hobby) = ('Tom', 21, 'game')

print(name, age, hobby)

<실행결과>

Tom 21 game



튜플을 선언할 때 () 를 넣지 않고 쉼표로만 구분해줘도 된다. 

(항목이 하나인 경우는 일반 변수와의 구별을 위해 뒤에 쉼표(,) 를 찍어줌)

a = 1, 2, 3
b = 4,

print(a)
print(b)

<실행결과>

(1, 2, 3)

(4,)




* 튜플의 삭제

del() 함수를 이용해서 튜플 자체 삭제 가능

t1 = (1,)

del(t1)


* 튜플은 값을 추가 하거나 변경할 수 없으므로 .append()등의 함수를 사용할 수 없음




* 튜플의 값 접근

리스트 처럼 [] 안에 인덱스를 입력해서 접근

범위를 지정해서 접근할 수도 있음

튜플의 덧셈과 곱셈도 가능


예)

tup1 = (1, 2, 3, 4, 5)
tup2 = (6, 7, 8 ,9)

print(tup1[1])
print(tup1[:2])
print(tup1 + tup2)
print(tup2 * 3)

<실행결과>

2

(1, 2)

(1, 2, 3, 4, 5, 6, 7, 8, 9)

(6, 7, 8, 9, 6, 7, 8, 9, 6, 7, 8, 9)



* 튜플과 리스트 변환

튜플과 리스트는 서로 변환할 수 있음

list(튜플) : 튜플을 리스트로 변경

yuple(리스트) : 리스트를 튜플로 변경

-> 튜플에 값을 추가해야 할 때는 튜플을 리스트로 변경한 후 값을 추가해 주고 다시 튜플로 변환


예)

tup = (1, 2, 3)
lst = [4, 5, 6]

# 튜플과 리스트의 상호 변환
tup = list(tup)
lst = tuple(lst)

print(tup)
print(lst)

# 튜플을 리스트로 변환한 후 값을 추가하고 다시 튜플로 변환
tup.append(4)
tup = tuple(tup)
print(tup)

<실행결과>

[1, 2, 3]

(4, 5, 6)

(1, 2, 3, 4)






4-4. 세트


세트(set, 집합) ({}) : 키만 모아 놓은 딕셔너리의 특수 형태. 중복이 되지 않으며 순서가 없음.



my_set = {1, 2, 3, 3, 3}

print(my_set)

<실행결과>

{1, 2, 3} 

(중복된 3은 무시)



*set는 {}로 묶어서 선언할 수도 있고 set()안에 리스트([])를 넣어서 선언할 수도 있다.


my_set = set([1, 2, 3])

print(my_set)

<실행결과>

{1, 2, 3}



* 세트에도 수학의 교집합, 합집합, 차집합을 적용할 수 있다.


.intersection() : 교집합

a = {1, 3, 5}
b = set([1, 2, 3])

print(a & b)
print(a.intersection(b))

<실행결과>

{1, 3}

{1, 3}



.union() : 합집합

a = {1, 3, 5}
b = set([1, 2, 3])

print(a | b)
print(a.union(b))

<실행결과>

{1, 2, 3, 5}

{1, 2, 3, 5}



.difference() : 차집합

a = {1, 3, 5}
b = set([1, 2, 3])

print(a - b)
print(a.difference(b))

<실행결과>

{5}

{5}



.symmetric_difference() : 대칭 차집합 - 겹치지 않는 값들

a = {1, 3, 5}
b = set([1, 2, 3])

print(a ^ b)
print(a.symmetric_difference(b))

<실행결과>

{2 ,5}

{2, 5}





.add() : 추가

a = {1, 3, 5}

a.add(7)
print(a)

<실행결과>

{1, 3, 5, 7}



.remove() : 제거

a = {1, 3, 5}

a.remove(1)
print(a)

<실행결과>

{3, 5}





4-5. 자료구조의 변경


type() : 데이터의 자료구조형 알려줌


a = [1, 2, 3]

print(type(a))

<실행결과>

<class 'list'>


*자료구조 변경하기 : 자료구조 이름() 을 통해서 자료구조를 바꿀 수 있다.


print(tuple(a))

print(set(a))

<실행결과>

(1, 2, 3)

{1, 2, 3}



* 컴프리헨션 (내포 표기)






댓글

이 블로그의 인기 게시물

Spring Boot 6. 계시판 프로젝트

Spring Boot 2. Maria 데이터베이스 & Spring Data JPA

Django 10. DB 연동