본문 바로가기

Algorithms and Languages/25-1 파이썬 알고리즘 코딩캠프

[알고리즘 코딩캠프 2일차] 정렬과 람다 - sorted(), list.sort(), lambda, 일급 객체, 2차원 리스트 - 초기화, 입력, 순회

제가 재학 중인 대학교에서 열린 `파이썬 알고리즘 코딩캠프(25.02.03 ~ 25.02.14)` 수업을 듣고 정리한 글입니다.

목차 :

  • 1일차 수업 내용 복습
  • 정렬과 람다
    • 오름차순&내림차순 정렬
      • sorted()
      • list.sort()
    • 커스텀 정렬 
      • lambda
      • 일급 객체
  • 2차원 리스트 
    • 2차원 리스트 초기화
    • 2차원 리스트 입력
    • 2차원 리스트 순회

 


1일차 수업 내용 복습

더보기
더보기
더보기

컨테이너 자료형들의 분류

순서가 있는 자료형 : 인덱스 접근 가능

순서가 없는 자료형 : 인덱스 접근 불가능

리스트 셋 딕셔너리 : 뮤터블 → 객체는 유지하고 내용을 바꿈

나머지(튜플, 문자열) : 이뮤터블 → 객체 자체가 바뀜, 즉 메모리에 새로 할당됨

리스트

list.pop(i)가 O(N)인건 최악의 경우(pop(0))이면 뒤에 꺼 하나씩 앞으로 밀어야 하니까. insert(i)도 마찬가지.

리스트에 쓰는 in 도 O(N)이라서 주의

a = {1 …} 일 때 list(a) 하면 O(N)임. 빈 리스트 만들고 append를 n번 해야하기 때문.

집합&딕셔너리

set.remove 가 왜 O(1)인가? list.remove는 O(N)인데?

→ 집합은 순서가 없으며 hash table구조이기 때문.

단, set()나 dict로 변환하는 거는 O(N). 빈 집합 만들어서 add.

왜 len()은 리스트든 집합이든 1이냐?

⇒ 파이썬의 구현체 CPython의 구조체 안에, 해당 자료형의 길이를 의미하는 변수가 들어있기 때문.


정렬과 람다 - sorted(), list.sort(), lambda, 일급 객체

오름차순&내림차순 정렬 - sorted(), list.sort()

더보기
더보기
더보기
# 오름차순 정렬
numbers = [1, 3, -4, 0, 100]
print(sorted(numbers))
numbers.sort()
print(numbers)

# 내림차순 정렬
numbers = numbers = [1, 3, -4, 0, 100]
print(sorted(numbers, reverse=True))
numbers.sort(reverse=True)
print(numbers)

커스텀 정렬 - lambda, 일급 객체

더보기
더보기
더보기
# 1. 기본 커스텀 정렬
words = ['hello', 'abc', 'z']
print(sorted(words))

def length(word):
    return len(word)
print(sorted(words, key=length))
# 주의!! 아래처럼 호출하면 안됨. 순수하게 함수 이름만 넘겨줘야함.
# print(sorted(words, key=length()))
print(sorted(words, key = lambda x:len(x)))
print(sorted(words, key = len))
# 위 코드들은 모두 동일하게 길이 기준으로 정렬함.


# 2. 리스트를 원소로 갖는 리스트 커스텀 정렬
numbers = [ [1, 13], [2, 7], [1, 7], [5, 10], [4, 20] ]
print(sorted(numbers))
# sorted는 2차원 리스트를 정렬할 때, 첫 번째 원소부터 보고,
# 같은 애들은 그 이후 두 번째, 세 번째, ... 끝까지 depth를 보고 정렬.

# 나는 앞에꺼 말고 무조건 뒤에꺼 기준으로 정렬하고 싶어!! 하면 아래처럼 짜면 됨.
def sort_key(unit):
    return unit[1]
print(sorted(numbers, key = sort_key))
print(sorted(numbers, key = lambda x: x[1]))

# 근데, 같은 우선순위에 대해선 앞에 거로 또 비교해서 정렬하면 좋겠는데??
def sort_key2(unit):
    return unit[1], unit[0] # 이거 반환형 튜플임! 소괄호 생력되어 있는 거.
print(sorted(numbers, key = sort_key2))
print(sorted(numbers, key = lambda x:(x[1], x[0])))

# 함수를 직접 정의하는 것과, 람다를 쓰는 것 둘 다 할 줄 알아야 함!!
# 람다로만 하기에는 복잡한 것도 있기 때문.


# 3. 람다 표현식

# 람다 == 함수 == 일급 객체(First Class Object)
# 아래 세 가지 특성을 만족하는 객체를 '일급 객체'라고 함.
# 즉, 함수는 일급 객체의 특성을 만족하며, 람다도 함수니까 일급 객체임.

# 1) 함수는 변수에 할당할 수 있다.
import sys
input = sys.stdin.readline
# 함수 이름 자체를 변수에 할당해 준 예시.

# 2) 함수는 인자로 넘길 수 있다.
def calculate_length(func):
    numbers = [1, 2, 3]
    length = func(numbers)
    print(length)

calculate_length(len)

# 3) 함수는 반환 될 수 있다.
def get_sum_function():
    return sum # sum을 반환함.

numbers = [5, 6, 7]
print(get_sum_function()(numbers))
# print(sum(numbers))와 동일.


# 람다(lambda)
def func1(x):
    return len(x)

func2 = lambda x:len(x)

numbers = [1, 2, 3, 4, 5]
print(func1(numbers)) # 5
print(func2(numbers)) # 5


# 계산기 만들기
operator = '+'
a, b = 100, 200

if operator == '+':
    print(a + b)
elif operator == '-':
    print(a - b)
elif operator == '*':
    print(a * b)
else:
    print(a / b)

# 이걸 람다를 사용해, 멋있게 구현 가능할까?
calculator = {
    '+': lambda x, y: x + y,
    '-': lambda x, y: x - y,
    '*': lambda x, y: x * y,
    '/': lambda x, y: x / y,
}

print(calculator[operator](a,b))
print((lambda x, y: x + y)(a, b)) # 이렇게도 가능

 


2차원 리스트

2차원 리스트 초기화

더보기
더보기
더보기
# 이차원 리스트
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

print(matrix[1][0])

matrix[1][0] = 10
print(matrix)

'''
[ 
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 0]
]
'''
# 위처럼 0으로 채워진 3x3 행렬로 초기화하고 싶은데, 어떻게 하면 좋을까?
# sol1(
matrix = []
for _ in range(3): #행(row)
    line = []
    for _ in range(3): # 열(col)
        line.append(0)
    matrix.append(line)
print(matrix)

# sol2)
matrix = []
for _ in range(3): #행(row)
    line = [0 for _ in range(3)]
    matrix.append(line)
print(matrix)

# sol3)
matrix1 = [[0 for _ in range(3)] for _ in range(3)]
print(matrix1)

# sol4)
matrix2 = [[0] * 3 for _ in range(3)]
print(matrix2)

# sol5)
matrix3 = [[0] * 3] * 3
print(matrix3)

# 근데... sol5)가 가장 짧으니 저게 젤 좋을까?
# 아무 문제가 없을까?????

matrix1[0][0] = 7
print(matrix1)

matrix2[0][0] = 7
print(matrix2)

matrix3[0][0] = 7
print(matrix3)

# matrix1 = [[0 for _ in range(3)] for _ in range(3)]
# matrix2 = [[0] * 3 for _ in range(3)]
# matrix3 = [[0] * 3] * 3

# matrix3은 얕은 복사로 같은 리스트 [0 0 0]를 가리키는 포인팅 객체가
# 뿅 뿅 뿅 하고 복사됨. [객체1, 객체2, 객체3] 인데 각 객체가 
# 동일하게 저 리스트 [0 0 0]을 가리키고 있는거

# matrix2에서 [7 7 7]이 되지 않는 이유는,
# 0은 이뮤터블이라 복사가 되지 않았기 때문.
# => 이거 다시 이해.

2차원 리스트 입력

더보기
더보기
더보기
# 1. 행렬 크기가 미리 주어지는 경우
'''
1 2 3
4 5 6
7 8 9
'''
import sys
input = sys.stdin.readline

# matrix = [list(map(int, input().split())) for _ in range(3)]
# print(matrix)



# 2. 행렬 크기가 입력으로 주어지는 경우
'''
3
1 2 3
4 5 6
7 8 9
'''
# N = int(input())
# matrix = [list(map(int, input().split())) for _ in range(N)]
# print(matrix)


'''
3 4
1 2 3 4
5 6 7 8
9 0 1 2
'''
# N, M = map(int, input().split())
# matrix = [list(map(int, input().split())) for _ in range(N)]
# print(matrix)

# 결국, 열의 개수에 대한 입력은 필요 없음.
더보기
더보기
더보기
# 문제를 잘못 이해했어서 중간에 뻘짓한 코드
# 만약 이걸 그대로 행렬로 하되 빈 자리는 0으로 채우라 하면
# 이렇게 하면 될 거임. 

'''
3
1 2 3
4 5 6
7 8 9
'''
'''
matrix = [[0 for _ in range(3)] for _ in range(4)]
for i in range(4):
    temp = list(map(int, input().split()))
    for j in range(len(temp)):
        matrix[i][j] = temp[j]
print(matrix)
'''

'''
3 4
1 2 3 4
5 6 7 8
9 0 1 2
'''
'''
matrix = [[0 for _ in range(4)] for _ in range(4)]
for i in range(4):
    temp = list(map(int, input().split()))
    for j in range(len(temp)):
        matrix[i][j] = temp[j]
print(matrix)
'''

2차원 리스트 순회

더보기
더보기
더보기
# 행 우선 순회 (행순회)
# => => => 로 행 별로 순회하겠다.
matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 0, 1, 2]
]
'''
1 2 3 4
5 6 7 8
9 0 1 2
'''
for i in range(3):
    for j in range(4):
        print(matrix[i][j], end = ' ')
    print() # 또는 print('')

for i in range(3):
    print(*matrix[i])
    # default는 아래처럼 됨
    # print(*matrix[i], sep = ' ')

print('======')
# 열 우선 순회 (열순회)
# ↓ ↓ ↓ ↓ 로 열 별로 순회하겠다.
matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 0, 1, 2]
]
'''
1 5 9
2 6 0
3 7 1
4 8 2
'''
# 로 출력되도록 해보자.

for i in range(4): # 열을 기준으로 먼저 보겠다!
    for j in range(3):
        print(matrix[j][i], end = ' ')
    print() # 또는 print('')
print('======')
#또는,
for j in range(4):
    for i in range(3):
        print(matrix[i][j], end = ' ')
    print() # 또는 print('')
# 그냥 아까 행 순회에서, 바깥과 안쪽의 for문을 바꿔주기만 하면 됨.

print('======')
# 이차원 리스트의 총합
matrix = [
    [0, 5, 3, 1],
    [4, 6, 10, 8],
    [9, -1, 1, 5]
]
# 이거 다 더했을 때 값 출력해보자.
total = 0
for i in range(len(matrix)): # 또는 3
    for j in range(len(matrix[0])): # 또는 4
        total += matrix[i][j]
print(total)
# 위 코드는 행 순회를 해서 풀었지만, 열 순회를 해서 풀 수도 있음.

# 위 코드를 아래처럼 행 단위로 축약해 풀 수 있음.
total = 0
for line in matrix:
    total += sum(line)
print(total)

# 위 코드를 아래 한 줄로 더 축약할 수 있음.
print(sum([sum(line) for line in matrix]))
# [sum(line) for line in matrix] <- [9, 28, 14] 와 같은 리스트

# 이걸 더 더 축약하면 아래처럼 됨.
print(sum(map(sum, matrix)))
# map(sum, matrix) <- sum을 matrix의 각 line에다가 적용한 결과인 map 객체

# 강사님 생각엔, 이건 위에 기초적인 것들이 익숙해진 뒤에 쓰자.

# 행렬의 최대값
print(max(map(max, matrix)))
# 행렬의 최소값
print(min(map(min, matrix)))

백준 2738번: 행렬 덧셈

https://www.acmicpc.net/problem/2738

더보기
더보기
더보기
# https://www.acmicpc.net/problem/2738
# 백준 2738번: 행렬 덧셈
# 풀이 1
import sys
input = sys.stdin.readline

# 입력 : 행렬의 크기 NxM
# 그리고 행렬의 원소들
# 출력 : 두 행렬을 합한 결과 행렬

N, M = map(int, input().split())
matrix_A = [list(map(int, input().split())) for _ in range(N)]
matrix_B = [list(map(int, input().split())) for _ in range(N)]

# matrix_sum = []
# for i in range(N):
#     line = []
#     for j in range(M):
#         line.append(matrix_A[i][j] + matrix_B[i][j])
#     matrix_sum.append(line)
    
# 리스트 컴프리헨션을 사용하여 행렬 합 계산
matrix_sum = [[matrix_A[i][j] + matrix_B[i][j] for j in range(M)] for i in range(N)]

for line in range(N):
    print(*matrix_sum[line])
# https://www.acmicpc.net/problem/2738
# 백준 2738번: 행렬 덧셈
# 풀이 2 - 더 효율적
import sys
input = sys.stdin.readline

# 입력 : 행렬의 크기 NxM
# 그리고 행렬의 원소들
# 출력 : 두 행렬을 합한 결과 행렬

N, M = map(int, input().split())
matrix_A = [list(map(int, input().split())) for _ in range(N)]
matrix_B = [list(map(int, input().split())) for _ in range(N)]

for i in range(N):
    for j in range(M):
        matrix_A[i][j] += matrix_B[i][j]

# 언패킹을 활용하여 출력
for line in matrix_A:
    print(*line)

과제 및 풀이 정리

<정렬>

https://cuffyluv.tistory.com/138

https://cuffyluv.tistory.com/142 (난이도 hard)

https://cuffyluv.tistory.com/143 (난이도 hard)

https://cuffyluv.tistory.com/146

<2차원 배열>

https://cuffyluv.tistory.com/139

https://cuffyluv.tistory.com/140