Golang - 슬라이스-2

Lumi·2022년 2월 11일
0

Golang

목록 보기
14/38
post-thumbnail

🔥 슬라이스 - 2

여기에서 또 문제점이 발생할수 있습니다.

앞서 설명한 예시와 같이 이전값을 공유하는 코드의 경우에는

  • Len값이 Cap값보다 작을떄 append적용

같은 주소값을 공유하기 떄문에 slice의 값이 바뀌게 되면 slice2의 값 또한 바뀐다는 점에 주의해야 합니다!!!!

흔히 하는 실수

func addNum(slice []int){
	slice = append(slice,4)
}

func main(){
	slice :=[]int{1,2,3}
    
    addNum(slice)
    fmt.Println(slice)
}

이런 상황에서는 값이 바뀌지 않습니다.

왜냐하면 append를 통해서 slice에는 또다른 주소값을 가진 데이터가 생성이 되기 떄문입니다.

  • 즉 인자로 들어간 slice와는 다른 slice주소값을 가지게 되고 인자값을 갱신해주지 않습니다.

좀더 쉽게 설명하면 인자로 들어간 slice와 인자를 받은 slice는 서로 다른 주소값을 가진다는 것으로 이해하면 되겠습니다.

  • 다른 주소값을 생성하고 메모리 값을 할당합니다.

만약 함수를 통해서 수정을 하고 싶다면 단순히 포인터와 주소값을 넘겨주기, 새로운 slice를 반환하기

  • 주로 반환하는 방식이 많이 쓰입니다.
  • 가독성이 좋으니깐(어떠한 변수를 사용하는지를 확인 가능)
  • 포인터 부분이 좀더 메모리적으로 이득이 되지만 사실상 차이가 없다.

슬라이싱

슬라이스를 잘라서 원하는 값만큼만의 슬라이스를 만들어 내는 행위 입니다.

array[startIdx : EndIdx 라는 구조를 가지고 잇습니다.

[1][2][3][4][5][6]

라는 array라는 슬라이스가 있다면

array[1 : 4]의 결과는

[2][3][4] 가 반환됩니다.
- 새로 만들어 지는 것이 아니라 주소값을 가르키는 변수가 반환이 되는 것 입니다.

실습 코드로 다루어 보면

	array := [5]int{1, 2, 3, 4, 5}

	slice := array[1:2]

	fmt.Printf("score : %d, length : %d, cap : %v \n", slice, len(slice), cap(slice))
	fmt.Println(array)

	slice = append(slice, 100, 100)
	fmt.Printf("score : %d, length : %d, cap : %v \n", slice, len(slice), cap(slice))
	fmt.Println(array)

	slice[2] = 200
	fmt.Printf("score : %d, length : %d, cap : %v \n", slice, len(slice), cap(slice))
	fmt.Println(array)


이런 코드를 동작시키면 slice의 값도 변경이 됩니다.
- 왜냐하면 같은 주소값을 가르키고 있기 떄문에

또한 이후 append작업한 이후에도 slice값을 변경시키면 array의 값도 변경이 됩니다.
- 둘은 같은 주소를 가지고 있기 때문에
  • 쉽게 이해하려면 깊은복사 상태이기 떄문에 같이 변경된다 정도로 이해를 하며
  • 부가적으로는 주소값이 같기 떄문에 바뀌는구나 정도로 이해하는 중입니다.

물론 배열만을 슬라이싱가능한 것이 아니라 슬라이도 또한 슬라이싱 가능합니다.

  • 사용법은 배열에 적용하는 것과 같습니다.

Cap사이즈를 조절할수 있는 방법도 있습니다.

slice[시작인덱스 : 끝인덱스 : 최대인덱스(cap)] 이런 구조로 사용이 가능합니다.

  • 최대 인덱스를 따로 지정하지 않으면 slice를 참고하는 변수의 cap값을 가지게 됩니다.

다른 주소값을 가지는 slice를 복사하기

slice1 := []int{1,2,3,4,5}

slice2 := slice1[:]
- 전체 복사

slice1[1] = 100

- 이러게만 하면 깊은복사와 같이 작동을 하기 떄문에 slice2의 값도 바뀌게 된다.

1. 순회하면서 직접 값을 넣어구지

      slice1 := []int{1,2,3,4,5}

      slice2 := make([]int, len(slice1))

      for i,v := range slice1{
          slice2[i] = v
      }

- for문을 활용하여 기존에 다른 주소값을 통해 초기화한 값에 넣어주는 방식

2. append를 활용

      slice1 := []int{1,2,3,4,5}

      slice2 := append([]int{}, slice1...)

- 이 또한 1번과 같이 작동을 하게 됩니다.
- 빈 슬라이스에다가 append를 하게 되고 slice1... 이런식으로 작동시키면 전체 요소가 다 들어가게 됩니다.
- 즉 slice1... == 1,2,3,4,5 와 같은 의미로 사용됩니다.


3. copy를 활용

	
      slice1 := []int{1,2,3,4,5}

      slice2 := make([]int, len(slice1))
      
      copy(slice2, slice1)
      - 앞에는 바꾸고자 하는 목적지, 뒷 인자는 넣어줄 값

이 방법들중 어떤게 좋냐라는 의미는 없습니다.

  • 상황에 맞게 사용을 하면 됩니다.

하지만 주로 copy를 많이 사용합니다.

  • 명확하기 떄문에

값 삭제

그냥 한개의 값을 뺴와서 삭제를 하는 작업은 불가능하고

값을 옮긴다음에 끝에잇는 값을 슬라이싱 하는 방식으로 작동을 합니다.

1, 2, 3, 4, 5

가 있는 상황에서 3을 삭제하고 싶다면

1, 2, 4, 3, 5 -> 1, 2, 4, 5, 3

으로 변형을 시킨뒤에 끝에있는 값을 슬라이싱 합니다.

slice:=[]int{1,2,3,4,5}
inx := 2

for i:=idx+1; i<len(slice); i++{
	slice[i-1] = slice[i]
}
// 여기까지 진행이 되면 1, 2, 4, 5, 3

slice = slice[:len(slice)-1]

이렇게 잘라주면 완성이 됩니다.

위 코드를 좀더 줄이면

slice := []int{1,2,3,4,5}
idx := 2

slice = append(slice[:idx], slice[idx+1:]...)

- slice[:idx]는 idx까지의 모든 value를 의미하고
- slice[idx+1:]... idx이후의 모든 value를 의미합니다.
- 즉 idx에 해당하는 value를 제외한 모든 값을 의미합니다.

요소 삽입

중간에 어떠한 값을 넣고 싶을떄 사용합니다.

1,2,3,4,5 라는 값이 있다면

1,2,3,3,4,5 로 변환시켜 주고

원하는 index자리의 값을 바꿔주면 됩니다.

slice := []int{1,2,3,4,5}

slice = append(slice, 0)
- slice = 1 ,2,3,4,5,0

idx := 2
- 추가할 부분

for i:=len(slice)-2; i>=idx; i--{
	slice[i+1] = slice[i]
}
- slice = 1,2,3,3,4,5

slice[idx] = 100

이 또한 한줄로 줄일수 있습니다.

slice := []int{1,2,3,4,5}
idx :=2

slice = append(slice[:idx], append([]int{100}, slice[idx:]...)...)

코드가 굉장히.. 어지럽지만 간단하게 정리를 하자면

일단 idx부분까지 append를 통해서 만들어 줍니다.

이후 저희는 100이 들어간 슬라이스를 넣어주면 되기 때문에 슬라이스를 만들어 주기 위해서 또다시 append를 사용합니다.

새로운 변수를 만들어주고 그값에 이제 slice의 이후의 값을 넣어줌으로써 작동을 하게 됩니다.

  • 사실 이 방식이 새로운 메모리를 할당하는 방식이기 떄문에 효율성에서는 많이 떨어지는 방식입니다..

그러기 떄문에 좀더 간단하게 하면

slice := []int{1,2,3,4,5}
idx :=2

slice := append(slice,0)
copy(slice[idx+1:], slice[idx:])

slice[idx] = 100
  • 방식이 코드가 간결하고 메모리적으로 소비가 많이 없는 방식입니다!!

정렬

많이 어려운 방식은 아닙니다.

  • 그냥 내부함수를 사용하면 됩니다.
import(
	"sort"
)

func main(){
	slice:= []int{5,2,6,3,1,4}
    sort.Ints(slice)
}

다른 문자나 실수 같은경우에는 Strings, Floats등을 활용 가능합니다.

profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글