본문 바로가기

코테 공부/python

[프로그래머스] Python 안전지대 / set.update(set) / zip()

 

https://school.programmers.co.kr/learn/courses/30/lessons/120866

 

나의 직독직해 구현 그 자체인 코드

def solution(board):
    answer = 0
    fix = []
    board_lim = len(board)

    # 수정할 이중배열 만들기
    for i in range(len(board)):
        fix.append([])
        fix[i] += [0 for j in range(board_lim)]

    # 돌면서 지뢰인 부분 찾아서 주변 위험지역으로 수정해주는 함수 소환
    for n in range(board_lim):
        for m in range(board_lim):
            if board[n][m] == 1:
                fix = dangerarea(n, m, board_lim, fix)

     # 보드 전체 개수에서 수정된 위험지역 배열의 위험지역 개수 모두 더한걸 빼서 안전 지대 구하기
    return board_lim * board_lim - sum([x for y in fix for x in y])

def dangerarea(n, m, board_lim, fix):
     # n, m으로 지뢰 인덱스 받아와서 위험지역 다 1인 fix 이중배열 반환
    fix[n][m] = 1

     # 지뢰 행 수정 좌우로 끝보다 큰지 여부에 따라 좌우 수정
    if m - 1 >= 0:
        fix[n][m - 1] = 1
    if m + 1 < board_lim:
        fix[n][m + 1] = 1

     # 세로 판단. 지뢰 위 행 수정
    if n - 1 >= 0:
        fix[n - 1][m] = 1
        if m - 1 >= 0:
            fix[n - 1][m - 1] = 1       
        if m + 1 < board_lim:
            fix[n - 1][m + 1] = 1

     # 세로 판단. 지뢰의 아래 행 수정
    if n + 1 < board_lim:
        fix[n + 1][m] = 1
        if m - 1 >= 0:
            fix[n + 1][m - 1] = 1
        if m + 1 < board_lim:
            fix[n + 1][m + 1] = 1

    return fix

 

스터디원의 깔끔한 코드

스터디원이 근접~ 이런 문제 나오면 dx dy 로 푼다고 하셨다.

크... zip()도 덕분에 처음 알게 되었다.

def solution(board):
    n = len(board)
    pos = set([])
    
    dx = [-1, -1, -1, 0, 0, 0, 1, 1, 1]
    dy = [1, 0, -1, 1, -1, 0, 1, 0, -1]
    
    for i, row in enumerate(board):
        for j, col in enumerate(row):
            if col == 1:
                for x, y in zip(dx, dy):
                    if 0 <= i + x < n and 0 <= j + y < n: 
                        pos.add((i + x, j + y))
    return n * n - len(pos)

스터디원은 set에 인덱스 구성을 추가할때 애초에 그 범위 안에 있는 인덱스 구성만 추가해준 반면

 

타풀이 코드

타풀이에서는 그냥 다 추가한 후에 그 값이 범위 안에 있는 인덱스만 나중에 세서 더해줬다는게 엄청... 멋지다.

def solution(board):
    n = len(board)
    danger = set()
    for i, row in enumerate(board):
        for j, x in enumerate(row):
            if not x:
                continue
            danger.update((i+di, j+dj) for di in [-1,0,1] for dj in [-1, 0, 1])
    return n*n - sum(0 <= i < n and 0 <= j < n for i, j in danger)

위에 있는 danger.update()

set.update(set)

두 set을 결합해 기존 set을 수정한다. 중복시 한번만 포함시킨다.

 

아니 comprehension이 list, dict, set 동일한 방식으로 가능한거 나만 이제 알았나..?!

set = {이 안에 comprehension 포현식}

dict = {key:val 이후에 표현식} 출력값 표시 형식이 key:val 형식으로 출력. 표현식은 for key, val in enumerate()/zip() 이런식으로

zip()

여러 개의 순회 가능한(iterable) 객체를 인자로 받고, 각 객체가 담고 있는 원소를 튜플의 형태로 차례로 접근할 수 있는 반복자(iterator)를 반환

 

nums = [1, 2, 3]
chars = ["A", "B", "C"]

print(zip(nums, chars))
# 결과
<zip object at 0x0000021F0D730340>


for pair in zip(nums, chars):
    print(pair)
# 결과
(1, 'A')
(2, 'B')
(3, 'C')

for x, y in zip(nums, chars):
    print(x, y)
# 결과
1 A
2 B
3 C

인자가 2개일 필요 없고 그 이상도 가능

nums1 = [1, 2, 3]
nums2 = [10, 11, 12]
Bchars = ["A", "B", "C"]
Schars = ["a", "b", "c"]


for pair in zip(nums1, Bchars, Schars, nums2):
    print(pair)
    
# 결과
(1, 'A', 'a', 10)
(2, 'B', 'b', 11)
(3, 'C', 'c', 12)

 

해체 하고 싶을 때도 zip() 함수 사용

리스트명 앞에 unpacking 연산자(*) 붙여서 다시 zip() 함수에 넘기면 다시 원래의 튜플을 얻을 수 있음

pairs = list(zip(nums, chars))
print(pairs)
# [(1, 'A'), (2, 'B'), (3, 'C')]

re_nums, re_chars = zip(*pairs)
print(re_nums)
# (1, 2, 3)
print(re_chars)
# ('A', 'B', 'C')

 

zip() 한걸로 dict(zip(인자, 인자)) 해서 두개의 리스트/ 튜플로 dictionary 만들 수 있음 (인자끼리 길이가 다르면 짧은것만 맞춰주고 버려짐)