Golang
[Golang] 슬라이스
GenieLove!
2022. 3. 4. 00:18
728x90
반응형
1.선언 및 초기화 방법
var slice []int
var slice1 []int{1, 2, 3}
var slice2 []int{1, 5:2, 10:3}//[1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3]//5인덱스의 값 2, 10인덱스의 값 3으로 할당
//var array [...]int{1, 2, 3}//배열은 앞에 ...
var slice3 = make([]int, 3)//길이 3짜리 int 슬라이스//[0, 0, 0]
2.append()
var slice = []int{1, 2, 3}
slice2 := append(slice, 4)
slice[2] = 6
fmt.Println(slice)//[1 2 6]
fmt.Println(slice2)//[1 2 6 4]
slice = append(slice, 4, 5, 6)
fmt.Println(slice)//[1 2 6 4 5 6]
3.슬라이스 내부 구현 - 슬라이스는 실제 배열을 가리키는 포인터를 가지고 있어, 쉽게 크기가 다른 배열을 가리키도록 변경 가능, 변수 대입 시 배열에 비해 사용되는 메모리, 속도에 이점이 있다.
type SliceHeader struct {
Data uintptr//실제 배열을 가리키는 포인터
Len int//요소 개수
Cap int//실제 배열 길이
}
var slice = make([]int, 2)// len 2, cap 2 -> 배열길이 2, 요소 개수 2
var slice2 = make)[]int, 2, 4)//배열길이 2 요소 개수 4 -> 나머지 2개는 나중에 추가될 요소를 위해 비워둠
4.함수 파라미터 전달 시 문제 - 슬라이스는 포인터로 접근하기 때문에 파라미터로 전달하여 값을 변경 시 기존에 있던 슬라이스 값도 같이 변경된다.(배열은 배열의 모든 값 복사, 슬라이스는 포인터도 복사된다)
func change(slice []int) {
slice[1] = 5
}
func main() {
s := []int{1, 2, 3}
change(s)
fmt.Println(s)//[1 5 3]
}
5.남은 공간에 따른 append차이
남은 공간 = cap - len
slice1 := make([]int, 3, 5)
slice2 := append(slice1, 6, 7)
//slice1 - len=3, cap=5
//slice2 - len=5, cap=5
//slice1, slice2 둘 다 같은 주소를 바라본다
slice1[1] = 20
fmt.Println(slice1)//[0 20 0]
fmt.Println(slice2)//[0 20 0 6 7]
slice1 = append(slice1, 9)
fmt.Println(slice1)//[0 20 0 9]
fmt.Println(slice2)//[0 20 0 9 7]//slice2값까지 바뀐다.
slice1 := []int{1, 2, 3}//len=3, cap=3
//남은 공간이 충분하지 않으면 기존 배열 크기의 2배로 만들고 기존 배열 값을 새로운 배열 값에 복사
slice2 := append(slice1, 4, 5)//len=5, cap=6 <- 2배로 복사돼서 cap이 3*2값이 됨
slice1[1] = 4
fmt.Println(slice1)//[1 4 3]
fmt.Println(slice2)//[1 2 3 4 5]//서로 다른 주소를 갖기 때문에 값 변경 X
6.슬라이싱 - 배열의 일부를 집어내는 기능(포인터로 접근되어 기존 배열(혹은 슬라이스)와 동일한 주소를 바라봐서 값이 같이 변경된다.)
slice[startIndex:endIndex]//시작 인덱스 ~ 끝 인덱스 - 1까지의 배열 일부
array := [5]int{1, 2, 3, 4, 5}
slice := array[1:3]
fmt.Println(array)//[1 2 3 4 5]
fmt.Println(slice)//[2 3]
slice[0] = 6
fmt.Println(array)//[1 6 3 4 5]
fmt.Println(slice)//[6 3]
slice = append(slice, 7)
fmt.Println(array)//[1 6 3 7 4 5]
fmt.Println(slice)//[6 3 7]
7.슬라이싱 방법
slice[시작인덱스:끝인덱스:최대인덱스]//cap 크기 조절 - cap = 최대인덱스 - 시작 인덱스
//원래는 cap = 끝인덱스 - 시작인덱스
8.독립적인 슬라이스 복제
slice1 := []int{1, 2, 3}
//첫번째 방법
slice2 := make([]int, len(slice1))
for i, v := range slice1 {
slice2[i] = v
}
//두번째 방법
slice2 := append([]int{}, slice1)
//slice2 := append([]int{}, slice1[0], slice1[1], slice1[2])과 같음
//세번째 방법 - copy이용
slice2 := make([]int, 2, 4)//len:2, cap:4
slice3 := make([]int, 5)//len:5, cap:5
//count2는 복사된 요소 개수
//copy(복사될 대상, 복사할 대상)
count2 := copy(slice2, slice1)//slice2의 요소개수 = 2, slice1의 요소개수 = 3 -> 둘 중 작은 값인 2개 복사//[1 2]
count3 := copy(slice3, slice1)//slice3의 요소개수가 더 많으므로 전체 복사//[1 2 3 0 0]
9.요소 삭제
slice := []int {1, 2, 3, 4}
index := 2
//첫번째 방법
for i := index + 1; i < len(slice); i++ {
slice[i - 1] = slice[i]
}
slice = slice[:len(slice)-1]
fmt.Println(slice)//[1 2 4]
//두번째 방법
slice = append(slice[:index], slice[index+1:]...)
10.요소추가
//slice[index+1:] = [3, 4 5]
//첫번째 방법 - [100, 3, 4 ,5]불필요 메모리 사용
slice = append(slice[:index], append({}int{100}, slice[index+1:]...)...)
//두번째 방법
slice = append(slice, 0)//맨 뒤에 요소 추가
copy(slice[index+1:], slice[:index])
slice[index] = 100
11.슬라이스 정렬
(1)int
slice := []int {5, 4, 3, 1, 2}
sort.Ints(slice)//Float64s()로 float64 슬라이스 정렬 가능
fmt.Println(slice)//[1 2 3 4 5]
(2)구조체
type User struct {
Name string
Age int
}
//첫번째 방법 - 정렬 인터페이스 이용
type Users []User
func (u Users) Len() int {
return len(u)
}
func (u Users) Less(i, j int) bool {
return u[i].Age < u[j].Age
}
func (u User) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
users := []User{
{"genie", 5}, {"babo", 40}, {"soomin", 28}
}
sort.Sort(Users(users))
//[{genie 5} {soomin 28} {babo 40}]
//두번째 방법 - 사용자 정의 Comparator이용
users := []User{
{"genie", 5}, {"babo", 40}, {"soomin", 28}
}
//sort.Slice()함수도 사용가능
sort.SliceStable(users, func(i, j int) bool {//true리턴 시 변경 X, false리턴 시 변경
return users[i].Age < users[j].Age
}
728x90
반응형