728x90
반응형

< 리스트 >

 

> 자료의 집합

개별 변수는 정수면 정수, 실수면 실수 식으로 딱 하나의 값만 저장하는 데 비해 리스트여러 개의 값을 집합적으로 저장한다.

다른 언어의 배열에 해당하며 실제로 배열과 비슷한 방식으로 사용한다.

[ ] 괄호 안에 요소를 콤마로 구분하여 나열함으로써 초기화한다.

 

score = [88, 95, 70, 100, 99]	# 다섯 개의 성적을 하나의 리스트에 저장
name = ["최상미", "이한승", "김기남"]	# 세 개의 이름을 하나의 리스트에 저장

* 개수의 제한이 없어 얼마든지 많은 변수를 모아서 저장할 수 있다.

 

리스트에 소속되는 각각의 값을 요소(Element) 또는 원소라고 한다.

리스트의 요소는 보통 같은 타입이지만 반드시 그런 것은 아니다.

사람 이름과 성적 처럼 다른 타입의 값을 섞어서 저장하는 것도 가능하다.

 

namescore = [ "최상미", 88, "이한승", 95 ]

* 이런식으로 쓸 수 있다는 것이지 일반적이지는 않다.

같은 타입의 값을 모아 두어야 실질적인 의미가 있고 현실적인 실용성이 있다.

 

# list score

score = [88, 95, 70, 100, 99]
sum = 0

for s in score:
    sum += s

print("총점:", sum)	# 총점: 452
print("평균:", sum / len(score))	# 평균: 90.4

빈 리스트는 [ ] 또는 list() 함수로 만든다.

요소를 전혀 가지지 않는 빈 리스트를 만들어 두고 실행 중에 요소를 추가할 수 있다.

list( ) 함수는 튜플이나 문자열 등 다른 타입을 리스트로 변환할 때도 사용한다.

문자열도 일종의 리스트인데 list( ) 함수로 문자열을 전달하면 개별 문자를 하나씩 쪼개 문자의 리스트를 만든다.

print(list("Korea"))    # ['K', 'o', 'r', 'e', 'a']

* "Korea" 를 구성하는 각각의 글자를 요소로 가지는 리스트가 생성된다.

 

> 리스트의 요소

리스트는 여러 가지 면에서 문자열과 유사한데 사실 문자열이 문자들을 모아 놓은 일종의 리스트이다.

그래서 리스트를 관리하는 방법은 문자열을 관리하는 방법과 비슷하며 문자열을 잘 다룰 수 있다면 리스트도 마찬가지 방법으로 다룰 수 있다.

 

score = [88, 95, 70, 100, 99]

print(score[0])  # 88
print(score[2])  # 70
print(score[-1])    # 99

* 요소의 순서 값을 매기는 방법이 문자열과 똑같고 첨자가 범위를 벗어나면 에러 처리되는 것도 같다.

[begin:end:step]

* begin 과 end 범위를 지정하되 범위의 끝은 포함되지 않는다.

# list slice

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

print(nums[2:5])    # [2, 3, 4]
print(nums[:4])  # [0, 1, 2, 3]
print(nums[6:])  # [6, 7, 8, 9]
print(nums[1:7:2])  # [1, 3, 5]
# list assign

score = [88, 95, 70, 100, 99]

print(score[2]) # 70
score[2] = 55   # 값 변경
print(score[2]) # 55
# list replace

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
nums[2:5] = [20, 30, 40]
print(nums) # [0, 1, 20, 30, 40, 5, 6, 7, 8, 9]
nums[6:8] = [90, 91, 92, 93, 94]
print(nums) # [0, 1, 20, 30, 40, 5, 90, 91, 92, 93, 94, 8, 9]
# range remove

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
nums[2:5] = []
del nums[4]
print(nums) # [0, 1, 5, 6, 8, 9]
# list cat

list1 = [1, 2, 3, 4, 5]
list2 = [10, 11]

listadd = list1 + list2
print(listadd)  # [1, 2, 3, 4, 5, 10, 11]

listmulti = list2 * 3
print(listmulti)    # [10, 11, 10, 11, 10, 11]

 

> 이중 리스트

리스트 요소에는 제약이 없어 숫자나 문자열은 물론이고 심지어 리스트 자체도 요소가 될 수 있다.

리스트끼리 중첩되는 셈인데 [ ] 괄호 안에 또 다른 [ ] 괄호를 넣으면 된다.

# nest list

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

print(lol[0])   # [1, 2, 3]
print(lol[2][1])    # 7

for sub in lol:
    for item in sub:
        print(item, end=" ")
    print()

# 1 2 3
# 4 5
# 6 7 8 9

* 리스트 안에 작은 리스트들이 포함되어 있다.

이 리스트가 메모리에 저장된 모습은 2차원 형태의 도표로 생각하면 된다.

 

# nest score

score = [
    [88, 76, 92, 98],
    [65, 70, 58, 82],
    [82, 80, 78, 88],
]

total = 0
totalsub = 0

for student in score:
    sum = 0
    for subject in student:
        sum += subject
    subjects = len(student)
    print("총점 %d, 평균 %.2f" % (sum, sum / subjects))
    total += sum
    totalsub += subjects

print("전체평균 %.2f" % (total / totalsub))

총점 354, 평균 88.50
총점 275, 평균 68.75
총점 328, 평균 82.00
전체평균 79.75

 

> 리스트 컴프리헨션

리스트 안의 요소가 일정한 규칙을 가지는 수열이라면 일일이 나열할 필요 없이 다음 문법으로 요소의 집합을 정의한다.

이 기능은 하스켈 언어의 문법에서 빌려 온 것이며 리스트 컴프리헨션(List Comprehension) 이라고 한다.

[ 수식 for 변수 in 리스트 if 조건 ]

[ ] 괄호 안에 요소를 생성하는 for 문과 if 문이 포함되어 있다.

내부의 리스트를 순회하며 각 요소에 대해 수식을 적용하여 최종 요소를 생성해 낸다.

if  조건은 그 중 일부 요소만 추려 내는데 필요 없을 시 생략 가능하다.

 

1 ~ 10 원소를 가지는 리스트라면 다음 식으로 선언한다.

[n for n in range(1, 11)]	# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

* for 문으로 1 에서 10 까지 순회하며 n 에 순서대로 대입하여 n 을 요소로 정의한다.

순회하는 값을 바로 취했으므로 1 ~ 10의 요소가 생성된다.

수식의 자리에서 순회값에 대한 식을 정의하면 변수를 원하는 대로 가공할 수 있다.

# list comp

nums = [n * 2 for n in range(1, 11)]

for i in nums:
    print(i, end=", ")	# 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,

* 1 에서 10 까지 순회하며 그 2배 되는 값을 취하여 출력

range 함수가 만들어 내는 범위의 각 요소에 2를 곱하였다.

1 에서 10 까지의 수에 대해 2 를 곱한 값이 리스트의 요소로 추가된다.

이 구문은 다음 코드와 같다.

nums = []
for n in range(1, 11):
    nums.append(n * 2)

 * 빈 리스트를 만들어 두고 범위에 대해 루프를 직접 돌며 범위의 각 값에 대해 2 를 곱한 값을 추가하면 된다.

이 구문을 간단하게 압축한 것이 위 예제의 구문이다.

 

일정한 조건을 지정하려면 뒤에 if 문을 붙이며 조건이 참인 요소만 리스트에 삽입된다.

1 ~ 10 의 값 중 3 배수만 취하려면 if 문에 n 이 3 의 배수라는 조건을 작성한다.

3 의 배수만 골라 그 제곱 값으로 구성된 리스트를 만들 수도 있다.

print([n for n in range(1, 11) if n % 3 == 0])
print([n * n for n in range(1, 11) if n % 3 == 0])

[3, 6, 9]
[9, 36, 81]

* 다른 언어에는 없는 재미있는 기능이지만 구문이 함축적이어서 난이도는 높은 편이다.

 


< 리스트 관리 >

 

> 삽입

리스트는 문자열과는 달리 변경 가능하다.

[ ] 괄호와 관리 메서드를 활용하여 요소를 마음대로 편집할 수 있다.

동작이 간단하고 직관적이므로 예제를 통해 구경만 해 보면 쉽게 익힐 수 있다.

# list insert

nums = [1, 2, 3, 4]

nums.append(5)
nums.insert(2, 99)

print(nums) # [1, 2, 99, 3, 4, 5]

* append 는 인수로 전달한 요소를 리스트의 끝에 덧붙여 추가한다.

insert 는 삽입할 위치와 요소값을 전달 받아 리스트의 중간에 삽입한다.

 

# insert range

nums = [1, 2, 3, 4]
nums[2:2] = [90, 91, 92]
print(nums) # [1, 2, 90, 91, 92, 3, 4] 삽입

nums = [1, 2, 3, 4]
nums[2] = [90, 91, 92]
print(nums) # [1, 2, [90, 91, 92], 4] 대체

* [ 2 : 2 ] 범위에 3 개의 요소를 대입했다.

범위의 끝은 제외 되기 때문에 [ 2 : 2 ] 범위의 길이는 사실상 0 이지만 삽입할 위치를 알려주는 역할을 한다.

길이 0 의 범위에 길이 3 의 리스트를 대입했으니 세 개의 요소를 삽입하는 것과 같다.

 

반면 [ 2 ] 번째 위치의 요소에 리스트를 대입하는 것은 효과가 완전히 다르다.

대입에 의해 요소가 바뀌며 2 번째 요소값이 길이 3의 리스트로 대체되어 요소 개수에는 변화가 없다.

리스트 끼리 중첩 가능하기 때문에 요소 자리에 리스트가 들어갈 수 있다.

 

리스트에 다른 리스트를 추가하여 병합할 때는 extend 메서드를 사용한다.

# extend

list1 = [1, 2, 3, 4, 5]
list2 = [10, 11]

list1.extend(list2)

print(list1)    # [1, 2, 3, 4, 5, 10, 11] 병합
list3 = list1 + list2   # 연결한 리스트를 리턴한다.
list1.extend(list2) # 직접 연결한다.

* + 연산자는 양쪽의 리스트는 건드리지 않고 두 리스트를 연결한 새로운 리스트를 리턴한다.

그래서 합친 결과를 별도의 변수로 대입받아야 한다.(list 3)

+  연산자로 똑같은 효과를 내려면 합친 결과를 자신이 다시 대입받아야 한다.

list1 = list1 + list2

 

반면 extend 메서드는 호출한 리스트에 인수로 주어진 리스트를 합친다.

 

> 삭제

리스트의 요소를 삭제할 때는 대상을 선택하는 방법에 따라 메서드를 골라 사용한다.

# list remove

score = [88, 95, 70, 100, 99, 80, 78, 50]

score.remove(100)
print(score)    # [88, 95, 70, 99, 80, 78, 50]
del(score[2])
print(score)    # [88, 95, 99, 80, 78, 50]
score[1:4] = []
print(score)    # [88, 78, 50]

* remove 는 인수로 전달받은 요소 값을 찾아 삭제한다.

해당 값이 없으면 예외를 발생시키고 값이 2개 이상이면 처음 발견한 요소 하나만 삭제한다.

 

del 명령은 순서값을 지정하여 삭제하며 할당의 반대 동작을 수행한다.

 

일정한 범위의 요소 여러 개를 지울 때는 범위에 대해 빈 리스트를 대입한다.

 

리스트의 모든 요소를 다 지워 리스트를 비울 때는 clear 메서드를 사용한다.또는 score[ : ] = [  ] 식으로 전체 범위에 대한 빈 리스트를 대입하거나del score[ : ] 명령으로 전체 범위를 다 삭제해도 효과는 같다.

 

# pop

score = [88, 95, 70, 100, 99]

print(score.pop())  # 99
print(score.pop())  # 100
print(score.pop(1)) # 95
print(score)    # [88, 70]

* remove 와 del 은 요소를 지우기만 하는 데 비해 pop은 삭제한 요소를 꺼내 리턴한다.

첨자를 지정하여 지울 대상을 지정하되 인수가 없으면 마지막 요소를 빼낸다.

인수를 생략하면 pop(-1)을 호출하는 것과 같다.

 

pop 은 요소를 삭제하면서 그 값을 다시 리턴하므로 리스트의 값을 순서대로 제거하며 읽을 때 유용한다.

리스트의 끝에서 append 로 추가하고 pop 으로 제거하면 선입 선출 방식으로 동작하는 스택(stack)이 된다.

 

pop(0) 호출로 리스트의 선두 요소를 빼내면 큐(Queue) 로도 사용할 수 있지만

쪽의 요소를 지우는 동작은 뒤쪽의 모든 요소를 이동시켜야하므로 느리고 비효율 적이다.

 

> 검색

리스트의 검색 메서드는 문자열의 경우와 거의 같다.

# list index

score = [88, 95, 70, 100, 99, 80, 78, 50]

perfect = score.index(100)
print("만점 받은 학생은 " + str(perfect) + "번입니다.") # 만점 받은 학생은 3번입니다.
pernum = score.count(100)
print("만점자 수는 " + str(pernum) + "명입니다.")   # 만점자 수는 1명입니다.

* index 는 특정 요소의 위치를 찾으며 발견되지 않을 경우 예외를 발생시킨다.

count 는 특정 요소값의 개수를 조사한다.

# list min

score = [88, 95, 70, 100, 99, 80, 78, 50]

print("학생 수는 %d명 입니다." % len(score))    # 학생 수는 8명 입니다.
print("최고 점수는 %d점 입니다." % max(score))  # 최고 점수는 100점 입니다.
print("최저 점수는 %d점 입니다." % min(score))  # 최저 점수는 50점 입니다.

* 리스트의 길이를 조사할 때는 len 내장 함수를 사용한다.

min, max 내장 함수는 리스트의 요소 중 최소값, 최대값을 찾는다.

 

# list in

ans = input("결제 하시겠습니까?")
if ans in ['yes', 'y', 'ok', '예', '당근']:
    print("구입해주셔서 감사합니다.")
else:
    print("안녕히 가세요.")

* 요소가 있는지 검사할 때는 in, not in 연산자를 사용한다.

사용자는 워낙 변화무쌍한 존재라 질문에 뭐라고 대답할지 정확히 알 수 없다.

가능한 모든 값에 대해 일일이 점검하여 or 논리 연산자로 결합하는 것이 원칙적이지만 코드가 너무 길고 장황하다.

 

> 정렬

정렬은 요소를 크기순으로 재배열하는 것이다.

# sort

score = [88, 95, 70, 100, 99]

score.sort()
print(score)    # [70, 88, 95, 99, 100] 오름차순
score.reverse()
print(score)    # [100, 99, 95, 88, 70] 내림차순

* sort 메서드는 리스트를 정렬하며 이 과정에서 요소의 순서가 조정되어 리스트 자체가 바뀐다.

reverse 메서드는 요소의 순서를 반대로 뒤집는다.

 

# sort_2

country = ["Korea", "japan", "CHINA", "america"]
country.sort()
print(country)  # ['CHINA', 'Korea', 'america', 'japan']

country.sort(key=str.lower)
print(country)  # ['america', 'CHINA', 'japan', 'Korea']
# sorted

score = [88, 95, 70, 100, 99]
score2 = sorted(score)

print(score)    # [88, 95, 70, 100, 99]
print(score2)   # [70, 88, 95, 99, 100] 오름차순

< 튜플 >

 

> 불변 자료 집합

튜플은 값의 집합이라는 면에서 리스트와 유사하지만 초기화한 후 편집할 수 없다는 점이 다르다.

그래서 튜플을 상수 리스트라고 부른다.

튜플을 정의할 때는 [ ] 괄호가 아닌 ( ) 괄호를 사용한다.

score = (88, 95, 70, 100, 99)

sum = 0
for s in score:
    sum += s

print("총점:", sum) # 총점: 452
print("평균:", sum / len(score))    # 평균: 90.4

> 튜플로 가능한 일

튜플의 요소를 읽는 것은 언제든 가능하다.

범위를 추출하여 일부를 잘라낼 수도 있고

+ 연산자로 튜플끼리 연결하거나

* 연산자로 튜플의 요소를 반복할 수도 있다.

그러나 튜플의 요소를 변경하거나 삭제하는 것은 불가능하다.

# tuple op

tu = 1, 2, 3, 4, 5

print(tu[3])    # 4
print(tu[1:4])  # (2, 3, 4)
print(tu + (6, 7))  # (1, 2, 3, 4, 5, 6, 7)
print(tu * 2)   # (1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
tu[1] = 100 # 변경 불가능
del tu[1]   # 삭제 불가능

* 리스타 제공하는 append 나 insert 같은 메서드가 없어 요소를 추가, 삽입할 수 없고 삭제도 할 수 없다.

튜플에서 제공하는 메서드가 index와 count 두 개 밖에 없어 요소를 찾거나 개수를 세는 것만 가능하다.

 

# unpacking

tu = "이순신", "김유신", "강감찬"

lee, kim, kang = tu

print(lee)  # 이순신
print(kim)  # 김유신
print(kang) # 강감찬

* 좌변에 변수 목록을 적고 우변에 튜플을 대입하면 튜플의 요소가 하나씩 변수에 대입된다.

이 기능을 사용하면 두 변수의 값을 한꺼번에 초기화할 수 있고 두 값을 쉽게 교환할 수도 있다.

 

# swap

a, b = 12, 34
print(a, b) # 12 34

a, b = b, a
print(a, b) # 34 12
# two return

import time

def gettime():
    now = time.localtime()
    return now.tm_hour, now.tm_min

result = gettime()
print("지금은 %d시 %d분 입니다" % (result[0], result[1]))
# div mod

d, m = divmod(7, 3)
print("몫", d)  # 몫 2
print("나머지", m)  # 나머지 1

* divmod 함수는 나눗셈의 몫과 나머지를 튜플로 묶어 리턴한다.

 

> 튜플을 사용하는 이유

튜플로 가능한일은 리스트로도 모두 가능하다.

값의 집합을 표현할 수 있고 요소를 변경하는 편집까지 가능하니 리스트는 튜플의 기능을 모두 포괄하는 더 큰 타입이다.

그럼에도 불구하고 굳이 변경 불가능한 튜플을 제공하는 데는 여러 가지 이유가 있다.

 

  1. 비용의 차이가 있다.
    리스트는 변경 가능성을 항상 대비해야 하므로 더 많은 메모리를 사용하고 속도도 느리다.
    이에 비해 튜플은 값의 집합만 표현할 뿐 바뀔 일이 없으므로 내부 구조가 훨씬 단순하고 읽는 속도도 빠르다.
  2. 편집할 수 없어 안정적이다.
    리스트는 실수나 불의의 사고로 언제든지 값이 바뀔 수 있지만,
    튜플은 한번 정해지면 절대로 바꿀 수 없어 실수할 위험이 없다.
    데이터베이스에서 읽었거나 네트워크로 받은 정보는 단순히 참조만하면 될 뿐
    편집할 일이 없으므로 리스트보다 튜플로 받는 것이 더 안전하다.
728x90
반응형

'Language > Python' 카테고리의 다른 글

Python_11. Collection Management  (0) 2022.08.03
Python_10. Dictionary and Set  (0) 2022.08.01
Python_08. String management  (0) 2022.07.31
Python_07. Function  (0) 2022.07.31
Python_06. Iteration  (0) 2022.07.27

+ Recent posts