[Algorithm] week5-day1: 당신의 list swap이 안 되는 이유

happy tiger·2022년 8월 24일
0

Algorithm

목록 보기
3/4
post-thumbnail

발단

wecode의 codekata week5-day1을 풀다가 해당 궁금증이 생겼다.
week5-day1 코드카타의 문제는 아래와 같다.

문제

정렬을 해야하는 배열은 [7,5,4,2] 입니다. 

첫 번째 loop에서는 index 0부터 3까지 확인하며 가장 작은 수를 찾습니다.
2 이므로 index 07과 교체합니다. -> [2,5,4,7]

두 번째는 index 1부터 3까지 확인하며 가장 작은 수를 찾습니다.
4이므로 index 15와 교체합니다 -> [2,4,5,7]

세 번째는 index 2부터 3까지.. 이런식으로 가장 작은 수를 선택해서 순서대로 교체하는 것을 선택정렬이라고 합니다.


# Problem Statement
nums라는 정렬되지 않은 숫자 배열을 주면, 오름차순(1,2,3..10) 으로 정렬된 배열을 return해주세요.
선택정렬 알고리즘으로 구현하셔야겠죠??

필자의 답안

def selectionSort(nums):
    for i in range(len(nums) - 1):
        min_num = min(nums[i + 1:len(nums)])
        if min_num < nums[i]:
          nums[nums.index(min_num)], nums[i] = nums[i], nums[nums.index(min_num)]
    return nums

궁금증

위의 답안은 성공적으로 nums=[64, 25, 12, 22, 11][11, 12, 22, 25, 64]로 바꾸어준다.
하지만 위의 코드에서 nums[nums.index(min_num)], nums[i] = nums[i], nums[nums.index(min_num)] 부분을 자리만 바꾸어서
nums[i], nums[nums.index(min_num)] = nums[nums.index(min_num)], nums[i] 로 실행하면 자리가 하나도 바뀌지 않고 [64, 25, 12, 22, 11]을 그대로 반환한다.
왜 그런 것일까??

해답 : 튜플의 unpacking

`a, b = c, d`의 진행순서는 이러하다.
  1. c, d의 값을 먼저 저장해둔다.
  2. c를 a에 대입한다. ( a = c )
  3. d를 b에 대입한다. ( b = d )
이 내용을 기억하고 아래의 두 코드를 다시보자.
nums = [0, 1, 2, 3, 4]

# 1번
nums[nums.index(4)], nums[2] = nums[2], nums[nums.index(4)]

# 2번
nums[2], nums[nums.index(4)] = nums[nums.index(4)], nums[2]

1번

1번의 진행상황을 뜯어보자.

  1. nums[2]nums[nums.index(4)]의 값을 저장해둔다.
    nums[2] = 2이고,nums[nums.index(4)] = nums[4] = 4이다.
  2. nums[nums.index(4)] = 2 대입을 진행한다.
    nums[nums.index(4)] = nums[4] = 2이므로, nums
    [0, 1, 2, 3, 4]에서 [0, 1, 2, 3, 2]가 된다.
  3. nums[2] = 4 대입을 진행한다.
    nums[2] = 4로 인해, nums는 [0, 1, 2, 3, 2]에서 [0, 1, 4, 3, 2]로 변경된다.

결과적으로 우리가 원했던 결과(4번 인덱스와 2번 인덱스의 swapt)가 나온다.

2번

이번엔 2번의 진행상황을 뜯어보자.

  1. nums[nums.index(4)]nums[2]의 값을 저장해둔다.
    nums[nums.index(4)] = nums[4] = 4이고, nums[2] = 2이다.
  2. nums[2] = 4 대입을 진행한다.
    nums[2] = 4로 인해, nums는 [0, 1, 2, 3, 4]에서 [0, 1, 4, 3, 4]로 변경된다.
  3. nums[nums.index(4)] = 2 대입을 진행한다.
    nums=[0, 1, 4, 3, 4]이므로 nums[nums.index(4)]nums[4]가 아닌 nums[2]가 된다.
    그 결과로, nums[2] = 2대입을 적용하면, nums
    [0, 1, 4, 3, 4]에서 [0, 1, 2, 3, 4]가 된다.

결과적으로 우리가 원했던 결과(4번 인덱스와 2번 인덱스의 swapt)가 아닌, 처음의 nums가 그대로 반환된다.

조심해야 할 부분

list의 index swap을 위해 우리는 a, b = c, d 형태를 사용하게 된다.
이 때, cd의 값을 저장한 후, 저장한 c의 값을 a에 대입하고, 그 후에 저장한 d의 값을 b에 저장한다.
그러므로, nums[nums.index(4)] 혹은 nums[nums[2]]와 같이 index 자리에서 다른 index를 불러오는 코드는 aba 자리에 위치하는 것이 좋다.
왜냐하면 다른 index를 불러오는 코드가, 대입으로 인해 영향을 받기 전에 진행되어야 오류가 없기 때문이다.

참고자료

stackoverflow-Tuple unpacking order changes values assigned

profile
호기심·끈기·성장·발전·행복·협력 ٩(๑•̀ㅂ•́)و

0개의 댓글