# Basics 배열의 비교 --- - 배열의 각각 요소의 값들이 동일한지 비교하기 위해서 `==` 로 비교할 수 있다. ```python= a = [1,2,3,4,5,6] b = [6,5,4,3,2,1] a == b # True ``` Reversed List --- - List를 반전하는 방법 1. a[::-1] 2. list(reversed(a)) ```python= a = [1,2,3,4,5,6] a[::-1] # [6,5,4,3,2,1] # if a != a[::-1]: return True ``` List Comprehension --- > 출처: https://shoark7.github.io/programming/python/about-list-comprehension-python - List Comprehension 이란 리스트를 쉽게, 짧게 한 줄로 만들 수 있는 파이썬의 문법을 의미한다. - 기본 문법 ``` [ ( 변수를 활용한 값 ) for ( 사용할 변수 이름 ) in ( 순회할 수 있는 값 )] ``` - 예시 ```python= # NOT list comprehension size = 10 arr = [0] * size for i in range(len(size)): arr[i] = i * 2 # list comprehension size = 10 arr = [i * 2 for i in range(size)] ``` - 조건문을 추가한 응용: 뒤에 if 문을 붙여주기만 하면 되지만, 특이한 점은 여러 조건문이 붙을 때 and 없이 써준다는 점이 특이하다. ```python= arr = [n for n in range(1, 31) if n % 2 == 0 if n % 3 == 0] ``` - 이중 for 문을 사용하는 방법 ```python= # 구조를 바꾸는 방법 (2차원 -> 1차원) - 첫번째 예제 flat_one = [n for row in arr for n in row] # 구조를 바꾸지 않는 방법 - 두번째 예제 [[n ** 2 for n in row] for row in arr] ``` - list comprehension 은 set, tuple, dict 에도 동일하게 적용될 수 있기 때문에 그냥 comprehension 이라고 부르는 것이 바람직할 수 있다. - python 에서 set 과 dict 는 같은 syntax ({}) 를 사용한다. 구분하는 방법은 초기화할 때, key-value 형태로 들어왔으면 dict로 인지하고, 그렇지 않은 경우 set 으로 인지한다. Iterable --- - 디자인 패턴 중 하나인 Iterator Pattern 에서 온 자료형이라고 볼 수 있다. - Iterator Pattern 은 정형화된 디자인 패턴이다. - Python 에서 대표적인 Iterable 자료구조는 아래와 같다. - List - Dict - Tuple - Set Magic Method (Special Method) --- - 리스트에서 예를 들어 `del` 이라는 키워드를 사용해서 element 를 지우는 경우가 있다. 여기서 `del`을 magic method 라고 부른다. - magic method는 Python 함수 중에서 __init__ 과 같이 2개의 underscore 로 시작하고 끝나는 함수를 의미한다. - 언제 magic method 를 사용할까? - 내가 만든 데이터 타입 (클래스)이 Iterable 자료형에서 사용되는 기능들 - 예를 들면, 슬라이싱, 반복문 등 - 을 동일하게 사용하고 싶을 때 - 예를 들어, Crypto 라는 클래스를 만들었다고 하면, Crypto + Crypto 는 market cap의 총합을 반환하도록 만들 수 있다. ```python= class Crypto: def __init__(self): self.market_cap = 0 def __init__(self, _market_cap): self.market_cap = _market_cap def __add__(self, _C): return self.market_cap + _C.market_cap def main(): btc = Crypto(1000) eth = Crypto (500) print ("total market cap is ", btc + eth) if __name__ == "__main__": main() ``` - 바인딩된 객체도 함수 형태로 호출할 수 있다. 이 때, `__call__()` 이라는 함수 안에 구현되어 있는 내용을 호출하게 된다. > 출처: https://wikidocs.net/83755 Lambda --- :face_with_monocle: Swap --- - python 에서 swap은 아래와 같이 매우 간단히 할 수 있다. ```python= a, b = 1, 2 a, b = b, a # 와우! ``` Quotient (몫) 연산 --- ```python= q = 100 // 3 # result: 33 ``` Python에서의 대소 비교 --- - 파이썬에서는 a<b<c 를사용할 수 있다. 너무 편리하다! len()을 남발하면 시간이 오래 걸릴 수 있다 --- - len() 을 너무 많이 호출하지 말자. 시간 소모가 많이 된다. 미리 값을 저장하거나 len 을 다른 변수로 define 해놓고 쓰는 방법도 있다. 이것이 시간을 줄일 수 있는 이유는 python 도 함수 search 를 해야하는데 len 을 찾는 시간 (lookup time)보다 정의된 함수를 찾는 것이 훨씬 유용하기 때문이다. > 출처: https://leetcode.com/problems/count-sub-islands/discuss/2172713/Python3-solution-connected-components Class의 대소 비교 --- ```python= class MyClass: def __init__(self, _key): self.key = _key def __gt__(self, c): return self.key > c.key def __lt__(self, c): return self.key < c.key def main(): c1 = MyClass(100) c2 = MyClass(200) if c1 > c2: print ("c1 is greater than c2") else: print ("c2 is greater than c1") if __name__ == "__main__": main() ``` 2차원 배열 사용하는 법 --- - [[False*100]*100] 이렇게 하면 같은 배열을 100개 복사하는 것이기 때문에 실제로 할당되는 공간은 100 크기의 하나 짜리 배열 뿐이다. 따라서 위와 같이 사용하면 안되고 for loop 을 사용해서 선언해야한다 ```python= visited = [[False for _ in range(200)] for _ in range(200)] ``` - 상하좌우를 방문할 때 다음과 같이 쓴다 ```python= dx = [-1, 1, 0, 0] dy = [0, 0, -1, 1] for x, y in zip(dx, dy): ... ``` 자료형의 데이터 추가 및 삭제 --- ```python= # 1. list arr = [] arr.append(val) # val 값을 list 의 마지막에 추가 arr.pop(idx) # idx 위치에 있는 값을 제거 후 반환 arr.remove(val) # val 이라는 값을 찾아서 제거. 반환 x arr.discard(val) # remove() 와 같지만, val 이 존재하지 않아도 에러를 띄우지 않음 del arr[idx] # idx 위치에 있는 값을 제거. 반환 x #2. dict mydict = {} mydict = dict() mydict[key] = val # key 를 갖는 val 추가 key in mydict # == key in mydict.keys() mydict.pop(key) # key 에 있는 값을 제거 후 반환 del mydict[key] # key 에 있는 값을 제거 #3. set myset = {} # dict 랑 선언하는 것은 같음. 단, 안에 비어있는 값이면 dict로 인식하기 때문에, 초기값을 넣어줘야한다. myset = set() # 만약 빈 set을 선언하고 싶으면 이렇게 선언한다 myset.add(val) # val 추가 myset.pop() # 정렬된 set 이기 때문에 idx 없이 pop 을 한다. myset.remove(val) # val 제거 myset.discard(val) ``` 중요한 사실 --- - dict 와 set 은 hash algorithm 에 따라서 저장되기 때문에 순서가 보장되지 않음. 단, 3.7부터는 저장되는 순서에 따라 저장되지만 근본적으로는 자료구조가 정렬은 안하는 순서로 있음. Dictionary 사용할 때 알아두면 좋은 것 --- #### defaultdict ```python= from collections import defaultdict d1 = defaultdict(int) d2 = defaultdict(list) d3 = defaultdict(str) ... ``` - Dict 클래스의 서브 클래스로 작동하는 방식은 거의 동일한데, 인자로 주어진 객체 (default-factory)의 기본값을 딕셔너리 초기값으로 지정할 수있음 - 초기값으로 들어올 수 있는 자료형은 숫자, list, set 등이다. - 언제 사용할까? - Key 가 존재하는지 확인하지 않아도 된다. 왜냐하면 없는 경우 자동으로 키를 만들어 주고 0으로 셋팅해주기 때문이다. #### setdefault ```python3= d = {} d.setdefault("mykey", "myval") ``` - 만약에 key 값이 없으면 default 값을 설정하도록 한다. - defaultdict() 보다 좀 더 설정할 수 있는 범위가 넓다. 반대로 생각하면, 더 심플한건 defaultdict() 이다. defaultdict의 경우 int면 자동으로 0 값으로 초기화시키기 때문이다. - return 으로 value 를 반환 Set --- ```python= A = set() B = set() A - B # 차집합 A & B # 교집합 A + B # 합집합 ``` - 두 개의 집합을 빼고 그 중에서 첫번째 값을 pop 하는 작업: (set(nodes) - set(children)).pop() - Set 의 pop 은 특정 위치에 있는 값이 아니라 첫번째 값을 pop 하도록 한다 pop() --- - list, set, dict 모두 pop의 기능을 제공한다. - list 에서 pop(idx) 은 특정 인덱스의 값을 꺼내는 역할을 한다 - set 에서의 pop() 은 배열처럼 어떤 인덱스를 주지 않고, 가장 먼저 들어갔던 값이 pop() 된다. - dict 에서의 pop(key) 은 특정 key의 값이 pop 된다 Pass by Reference --- - list, set, dict 와 같은 자료형들은 function 으로 넘길 때 copy 되지 않고 pass by reference 로 이동한다. 따라서 이러한 자료형을 넘겨줄 때는 항상 고민해야한다. - binary tree의 경로 문제에서 모든 경로를 지정해야될 때, bit matching을 사용해서 이 문제를 해결할 수 있다. depth가 32를 넘어가지 않는다면, 32bit 정수로 모든 경로를 표현할 수 있다. 또한, 그 값이 1과 0또는 갖는다면? 그리고 정수는 Pass by Value이기 때문에 값을 내가 일부러 복사해야하는 불편함은 제거할 수 있다. ```python= def dfs(node, path): if not node: return path = path^(1 << node.val) if not node.left and not node.right: if path & (path-1) == 0: self.count += 1 else: dfs(node.left, path) dfs(node.right, path) ``` > 원본 위치: > - https://leetcode.com/problems/pseudo-palindromic-paths-in-a-binary-tree/discuss/2129422/Python-(Simple-DFS)> > - https://codingdog.tistory.com/entry/%EB%B9%84%ED%8A%B8-%EB%B0%B0%EC%97%B4-%EA%B3%B5%EA%B0%84%EC%9D%84-18-132-164%EB%A1%9C-%EC%95%95%EC%B6%95%ED%95%9C%EB%8B%A4 DFS 를 사용할 때 고려해야 될 것 1) Dfs 가 끝나고 결과에 따라서 값을 바로 반환해야하나? (pruning 을 해야하나) --> sub island 문제 2) DFs 가 종료되는 condition 과 DFS 를 들어갈 때 condition 이 중첩되지 않도록 해야한다: 언제 들어가고, 들어가서 뭘하고, 다음 dfs 는 어떤 조건에서 호출되는지