리스트 정렬

sort 함수와 sorted함수

- ?.sort 함수는 list타입인 ? 의 요소를 오름차순으로 정렬한다

- ?.sort(reverse = True)함수는 내림차순으로 정렬한다

- sort함수와 sorted함수는 거의 같다

- ?.sort() 함수는 ?의 속성을 바꾸지만 sorted() 함수는 ?의 속성을 바꾸지 않는다 (a.append()와 + 연산의 차이)

a = [1, 5, 2, 3, 7, 4]
print(a)
[1, 5, 2, 3, 7, 4]
a.sort()
print(a)
[1, 2, 3, 4, 5, 7]
a.sort(reverse = True)
print(a)
[7, 5, 4, 3, 2, 1]

- sort, sorted의 key 옵션에 지정된 함수의 결과에따라 정렬한다

- lambda함수(익명 함수) 사용 ---> lambda 매개변수: 결과

b = [(1, 2), (0, 2), (1, 3), (1, 5), (0, 1), (2, 8)]
c = sorted(b, key = lambda x: (x[0], -x[1])) ## x[1]앞에 있는 '-'기호는 현재정렬순서와 반대로이다
print(c)                                     ##첫 번째 원소는 오름차순, 두 번째 원소는 내림차순으로 정렬
[(0, 2), (0, 1), (1, 5), (1, 3), (1, 2), (2, 8)]

reverse 함수

- ?.reverse 함수는 list형태인 ? 의 요소를 역순으로 정렬한다

d = [1, 5, 2, 3, 7, 4]
d.reverse()
print(d)
[4, 7, 3, 2, 5, 1]

reversed 함수

- reversed 함수는 요소를 역순으로 정렬해 반환한다

- 반환값을 그대로 사용하지 않고 list()tuple()함수를 통해 사용한다

d = [1, 5, 2, 3, 7, 4]
reversed(d)
<list_reverseiterator at 0x179d8c11f10>
d = [1, 5, 2, 3, 7, 4]
print(tuple(reversed(d)))
(4, 7, 3, 2, 5, 1)

리스트 초기화

1차원 리스트

a = [] ## 빈 리스트로 초기화
print(a)
[]
A = [x] * n

- $A = [x, x, x, \cdots, x, x] \longrightarrow$ $x$가 $n$개인 $1$차원 리스트

a = [0]*10 ## 0리스트로 초기화
print(a)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

2차원 리스트

n = 5
list_ = [[0] * n for _ in range(n)] ## 0으로 채원진 2차원 리스트
list_
[[0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0]]
list_[0][0] = 123
list_
[[123, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0]]
List = [[0] * 5 for _ in range(5)

- 그런데 _ 는 뭐지?

- 사실 _ 자리에 다른 것이 들어가도 된다 이를 테면 i

x = [0*i for i in range(5)]
print(x)
[0, 0, 0, 0, 0]

- 위에 List에서 _ 대신에 i를 넣는다고 생각하자

List = [[0] * 5 for i in range(5)

- 위에 리스트인 x 에서는 i가 리스트 안에 0몇 개 생성할 지 정하는 변수였다

- 위에 리스트인 List 에서는 i가 무슨 역할을 하지??

- 아무역할도 하지 않는다

- 0을 5개 생성하고 이를 5번 반복한다

- List를 정의할 때 부터 정해졌다

- i는 그저 for문을 쓰기 위해 필요함 ---> range(5)의 값을 받아낼 변수가 필요하다

- 그래서 i 자리에 오는 변수는 아무짝에도 쓸모가 없다

- 아무 의미가 없어서 그냥 아무 의미 없어보이는 기호인 _를 쓴다(내 생각)

리스트 추가

?.append()

- ? ---> 리스트

- 마지막(?[-1]) 위치에 하나의 원소 추가

a = []
a.append(1)
print(a)
[1]

?.insert(i, v)

- i 위치에 v 원소 추가

b = [1, 2, 3, 5, 6, 7]
b.insert(3,4)
print(b)
[1, 2, 3, 4, 5, 6, 7]

?.extend()

- 마지막(?[-1]) 위치에 리스트 추가

c = [1, 2, 3, 4, 5]
c.extend([6, 7, 8])
print(c)
[1, 2, 3, 4, 5, 6, 7, 8]

?.pop()

- pop(i)는 리스트의 i번째 요소를 돌려주고 그 요소는 삭제, pop() = pop(-1)

d = [1, 2, 3, 4 ,5]
x = d.pop()
print(x)
print(d)
5
[1, 2, 3, 4]

arr[::] 용법

- 슬라이싱 방법임

- arr[A:B:C] ---> index A부터 index B(포함X)까지 C간격으로 arr 생성

- A가 none이면 처음부터 B가 none이면 끝까지 C가 none이면 1만큼

- 참고: https://docs.python.org/release/2.3.5/whatsnew/section-slices.html

arr = list(range(10))
print(arr)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr[1:9:2]
[1, 3, 5, 7]
arr[:10:3]
[0, 3, 6, 9]
arr[1::2] ## arr[1:2]와 결과가 동일함
[1, 3, 5, 7, 9]
arr[1:5:]
[1, 2, 3, 4]
arr[5::] ## arr[5:]과 결과가 동일함
[5, 6, 7, 8, 9]
arr[5:]
[5, 6, 7, 8, 9]
arr[:3:]
[0, 1, 2]
arr[::4] ## arr[:4]와 결과가 동일함
[0, 4, 8]
arr[:4]
[0, 1, 2, 3]
arr[::] ## arr[:]과 결과가 동일함
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

다차원에서의 사용

- 다차원 matrix에서의 사용도 동일함

- 리스트에서 [ ]를 영역마다 사용하여 슬라이싱 ---> ex) list[0:2][0:2][0:2]

- 참고: https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html

arr1 = [[1, 2, 3], [2, 3, 4], [3, 4, 5]] ## arr1은 (3, 3)차원 ## arr1(a, b) ---> a는 1차원 b는 2차원 ---> a는 x축 b는 y축이라 생각해도 됨 
arr1[0:2][0:2] ## x축에서 0~1까지, y축에서 0~1까지 리스트를 슬라이싱함
[[1, 2, 3], [2, 3, 4]]
arr2 = [[[1, 2, 3], [2, 3, 4]], [[3, 4, 5], [4, 5, 6]], [[5, 6, 7], [6, 7, 8]]]
arr2[0:2][0:2][0:2] ## x축에서 0~1까지, y축에서 0~1까지, z축에서 0~1까지 리스트를 슬라이싱함
[[[1, 2, 3], [2, 3, 4]], [[3, 4, 5], [4, 5, 6]]]
arr2[:][1][0:2] ## x축에서 처음부터 끝까지, y축에서 1, z축에서 0~1까지 리스트를 슬라이싱함
[[3, 4, 5], [4, 5, 6]]

numpy에서의 사용

import numpy as np
arr3 = np.array(arr2)
print(arr3)
[[[1 2 3]
  [2 3 4]]

 [[3 4 5]
  [4 5 6]]

 [[5 6 7]
  [6 7 8]]]
arr3.shape ## arr3는 (3, 2, 3)차원의 matrix임
(3, 2, 3)

- list에서는 [ ]영역마다 사용했지만 numpy array에서는 하나의 [ ] 안에서 표현 가능

- numpy array에서는 콤마(,)로 영역을 구분하고 :를 통해 슬라이싱을 함 ---> ex) numpy_array[0:2, 0:2, 0:2]

- list[0:2][0:2][0:2] ---> 리스트에서 슬라이싱

- arr[0:2, 0:2, 0:2] ---> numpy array에서 슬라이싱

- 둘다 의미는 x축에서 0~1까지, y축에서 0~1까지, z축에서 0~1까지 array를 슬라이싱하라는 뜻

arr3[1, 1 ,1] ## 기본적인 인덱싱 방법
5
arr3[0:2, 0:2, 0:2] ## x축에서 0~1까지, y축에서 0~1까지, z축에서 0~1까지 array를 슬라이싱함
array([[[1, 2],
        [2, 3]],

       [[3, 4],
        [4, 5]]])
arr3[:2, :1, :] ## x축에서 처음부터 1까지 y축에서 처음부터 0까지, z축에서 처음부터 끝까지 array를 슬라이싱함
array([[[1, 2, 3]],

       [[3, 4, 5]]])

- 어떤 array가 있는데 마지막 차원에서 인덱스가 마지막 번호인 array만 슬라이싱하고 싶다고 하자

- 아래와 같이 해도 됨

arr3[:, :, -1] ## 1차원의 모든 원소, 2차원의 모든 원소, 3차원은 마지막 원소만 가지는 array를 슬라이싱함
array([[3, 4],
       [5, 6],
       [7, 8]])

- numpy array에서는 ,를 통해 차원의 구분을 하고 :를 통해 슬라이싱을 함

- 근데 차원이 매우 크다면?

- 예컨데 차원이 100차원이라면 일일이 :,를 입력할 것인가? ---> 궁금한건 마지막 차원에 대한 조건임, 더 작은 차원은 무관심

- 어떻게 함?? ---> ...(ellipsis)를 사용

- ...은 우리가 일일이 입력해야할 앞의 차원에서의 :,을 의미함 + ...을 뒤에 입력하면 뒤의 차원을 커버함 ---> 하나의 [ ]안에서 한 개만 사용 가능

arr3[..., -1] ## ...은 앞의 차원들의 원소를 모두 포함한다는 의미
array([[3, 4],
       [5, 6],
       [7, 8]])
arr3[..., 0:2]
array([[[1, 2],
        [2, 3]],

       [[3, 4],
        [4, 5]],

       [[5, 6],
        [6, 7]]])
arr3[1, ...] ## 1차원에서 인덱스가 1인 array를 추출, 뒤에 차원들의 원소는  ...을 사용하여 모두 포함했음 
array([[3, 4, 5],
       [4, 5, 6]])

슬라이싱을 사용해 이미지의 RGB값 거꾸로하기

- 이 문제 때문에 ellipsis에 대해 알아봄

- OpenCV를 통해 이미지를 불러온다고 해보자

- OpenCV에서는 컬러 이미지BGR 순서로 저장함

- plt.imshow()로 이미지를 확인할 것임

- 그런데 matplotlib에서는 RGB 순서로 저장함 ---> RGB순서가 바뀜(흑백 사진은 괜찮음)

- 즉 OpenCV로 읽어온 이미지를 RGB순서로 바꿔야 함

import matplotlib.pyplot as plt
import cv2 as cv

img = cv.imread('squirrel.jpg')
plt.imshow(img)
<matplotlib.image.AxesImage at 0x2737ecd7880>

- cv.imread()를 통해 이미지를 읽어오는데 이 함수가 RGB순서가 아닌 BGR순서로 이미지를 읽어서 원본과 다르게 보이는 것임

- 이미지도 숫자 matrix임 ---> BGR순서만 RGB로 할 수 있을까?

- 만약 어떤 array가 있는데 나머지는 그대로 두고 마지막 차원의 원소의 순서만 반대로 하고 싶다면?? ---> ...을 활용하자

- img[..., ?]과 같이 하면 일단 마지막 차원의 원소를 제외하고 모두 그대로임

- 이제 제어할 차원이 하나 남음 ---> 벡터와 마찬가지

- 1차원 array의 순서를 거꾸로 하려면??? ---> array[ : : -1] ---> 처음부터 끝까지 음의 방향으로 리스트 슬라이싱

img2 = img[..., ::-1] 
plt.imshow(img2) ## 원본 이미지가 보임
<matplotlib.image.AxesImage at 0x2737ee0c340>

- 원본 이미지가 제대로 보임

리스트 삭제

?.remove(x)

- 리스트에서 x원소를 삭제

- 삭제할 원소가 없을 시 error

a = [1, 2, 3, 4, 5, 6]
a.remove(1)
print(a)
[2, 3, 4, 5, 6]
a.remove(10)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-2-72b3315abecc> in <module>
----> 1 a.remove(10)

ValueError: list.remove(x): x not in list

문자열 포함여부

?.find('문자열')

- ?문자열이 존재하면 가장 앞에 원소의 시작 인덱스 값을 반환하며 존재하지 않으면 -1값을 반환

day = '2021-07-03'
day.find('2021')
0
day.find('-')
4
day.find('2222')
-1

'문자열' in ? , '문자열' not in ?

- ?문자열이 존재하면 True 반환, 존재하지 않으면 False 반환, not in에 경우는 반대로

day = '2021-07-03'
'2021' in day
True
'-' not in day
False
'2222' in day
False
list = ['1011', '2022', 'day', 'model']
'2022' in list
True
'day' not in list
False
'month' in list
False

enumerate 함수

- for문을 사용할 때 인덱스를 같이 출력할 수 있음

- 참고: 파이썬 for문

cards = ['A', 'B', 'C']

for i in range(len(cards)):
    print(i, cards[i])
0 A
1 B
2 C
for value in enumerate(cards):
    print(value)
(0, 'A')
(1, 'B')
(2, 'C')

- enumerate 함수는 인덱스와 원소로 이루어진 tuple을 생성함

- 만약 인덱스와 원소를 다른 변수로 만들고 싶다면 tuple unpacking을 사용하면 됨

for idx, card in enumerate(cards):
    print(idx, card)
0 A
1 B
2 C

zip 함수

- zip 함수는 iterable한 객체들을 인자로 받아 각각의 원소를 tuple로 접근가능한 iterator를 만듦

- 참고: python zip function

a = ('John', 'Charles', 'Mike')
b = ('Jenny', 'Christy', 'Monica')
zip(a, b)
<zip at 0x179d8b6d100>
list(zip(a, b))
[('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica')]
tuple(zip(a, b))
(('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica'))