# 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 는 어떤 조건에서 호출되는지