[Code Kata] 선택정렬 & 인덱스 참조를 이용한 튜플 패킹시 주의사항

do yeon kim·2022년 8월 24일
0
튜플을 이용한 인덱스 swap시 주의사항 & 인텍스이용한 튜플패킹시 주의사항

코드를 구현 중 인덱스를 이용해서 튜플 패킹을 해서 값을 swap 할 때 값이 변하지 않을 수도 있다는 것을 알게 되었다.


문제가 되는 코드는 아래와 같다.


#첫번째 경우 1
nums[nums.index(min_num)], nums[i] = nums[i], nums[nums.index(min_num)]

#두번째 경우 2
nums[i], nums[nums.index(min_num)] = nums[nums.index(min_num)], nums[i]

두개의 코드가 결과적으로 구현하고자 하는 것은 값을 swap해주는 것이다.
하지만 첫번째의 경우는 값이 변경되지만, 두번째의 경우는 값이 변경되지 않는다.

단순히 작성한 위치를 변경했을 뿐인데 두개의 결과 값이 다르다.

처음에는 왜 이런 문제가 발생하는지 감도 잡히지 않았다.
직접 다른 예를 들어가면서 해결해보려고 했다.
원하는 결과는 아래와 같았다.

nums = [1,2,3,4,5]
nums[0], nums[1] = nums[1], nums[0]
print(nums)
[2,1,3,4,5]

nums = [1,2,3,4,5]
nums[1], nums[0] = nums[0], nums[1]
print(nums)
[2,1,3,4,5]

순서를 바꾸어도 결과가 첫번째 경우, 두번째 경우 모두 바뀌는 것을 확인 할 수 있었다.

앞의 문제가 발생한 코드의 경우와 위의 예시가 다른 점은 인덱스를 이용했다는 점이므로 그 부분을 초점을 맞추어서 구글링을 시작했다.


https://stackoverflow.com/questions/34171348/tuple-unpacking-order-changes-values-assigned

문제의 원인은 동작 순서에 있었다. 동작 순서로 인해 side effect가 발생해서 값이 변경되지 않았던 것이다.

튜플의 패킹의 값을 할당하는 순서는 a, b = c, d일 경우

c와 d가 먼저 저장된 뒤 a에 c를 할당한다. 그리고 마지막으로 b에 d를 할당한다.

이때 인덱스를 이용한 패킹시 a값이 c로 변경된 상태의 리스트 내에서 다시 b에 d를 할당하기 때문에 변경이 이루어지지 않는것이다.



예를 들어 nums = [1, 2, 3, 4, 5] 이 있다고 하자!!!
인덱스와 튜플 패킹을 이용해서 1과 2의 자리를 바꾸도록 해보자!!!!
1의 인덱스는 nums.index(1)
2의 인덱스는 nums.index(2)

nums[nums.index(1)], nums[nums.index(2)] = nums[nums.index(2)], nums[nums.index(1)]

nums[nums.index(2)] 은 2
nums[nums.index(1)] 은 1 이 저장된다.

nums[nums.index(1)] 에 먼저 2가 저장되면서

nums = [2, 2, 3, 4, 5] 가 된다.
그리고 다음의
2의 있는 것은 0번째 인덱스이므로 다시 1이 저장된다
nums[nums.index(2)]에 다시 1이 저장된다.

nums = [1, 2, 3, 4, 5] 가 된다.

결과가 바뀌지 않는 것을 알 수 있다.


그러므로 튜플의 패킹을 이용해서 값을 swap하고자 하며, index를 이용해서 특정 위치를 참조하는 코드를 구현하는 경우라면, 패킹이 순서대로 진행되기 때문에 앞의 값이 먼저 변경된 후의 값을 뒤의 값을 저장시 인덱스가 참조 할 수 있으므로 주의가 필요하다.



선택정렬

순서가 없는 데이터의 순서를 정렬하는 방법 중 하나이다.
선택정렬이외에 버블정렬, 삽입정렬, 퀵정렬 등이 있다.

nums = [12, 4, 20, 1]

먼저 리스트 내의 최소 값을 찾는다. 이 경우 1 이된다.
최소값을 제일 앞의 값과 swap 해준다.

첫번째 라운드 결과 nums = [1, 4, 20, 12]

제일 앞의 값을 제외한 값 들 중 최소값을 찾는다.
다음의 최소값은 4 가 된다.

하지만 남은 값 중 4가 최소값 이므로 변경사항은 없다.
두번째 라운드 결과 nums = [1, 4, 20, 12]

앞의 두개의 값을 제외한 값 들 중 최소값을 찾는다.
다음의 최소값은 12가 된다.
세번째 라운드 결과 nums = [1, 4, 12, 20]


코드 구현
nums = [3,5,1,4]

def selectionSort(nums):
    count = 0 # 몇번 동작하는지 확인 하기 위한 count변수
    for i in range(len(nums)): # nums의 요소의 수 만큼 반복하게 한다.
        min_num = min(nums[i:len(nums)])
        
        #if문을 활용해 최소값이 맞는지 확인한다.
        if min_num < nums[i]: 
            # nums[i],nums[nums.index(min_num)] = nums[nums.index(min_num)],nums[i]
            
            # 맞다면 튜플패킹을 이용해서 swap 해준다.
            nums[nums.index(min_num)],nums[i] = nums[i], nums[nums.index(min_num)] 
            # 패킹을 통해 리스트의 값을 swap 해준다. 
            count += 1
    return nums, count
    
result = selectionSort(nums)
print(result)

min_num = min(nums[i:len(nums)])

반복문을 한 번 돌때마다, 최소값들이 앞에 정렬된다.
그러므로 nums를 슬라이싱 해서 새로운 nums를 만들어서 그 리스트 안에서 최소값을 찾아야 한다.

  • 첫번째 min(nums[0:4])
    nums = [3, 5, 1, 4]

  • 두번째 min(nums[1:4])
    nums = [5,3,4]

  • 세번째 min(nums[2:4])
    nums = [5,4]

0개의 댓글