일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- LOB
- 운영체제
- C++ library
- JUCE
- 프로그래밍
- JUCE라이브러리
- go
- 리듬게임
- 자료구조
- vim-go
- c++ heap
- JUCE 튜토리얼
- C++ gui 라이브러리
- C++
- 코딩
- 연결리스트
- 백준
- Docker
- 알고리즘
- tour of go
- BOJ
- C++ gui
- a tour of go
- Nebula
- JUCE library
- C언어
- 공룡책
- OS
- gui
- go channel
Archives
- Today
- Total
CafeM0ca
[Go] sort In struct and map 본문
반응형
Go언어 Sort. 구조체 정렬, map 정렬
Go의 Sort를 알아보자.
기본적으로 int형 slice와 float64형 slice, string slice는 Sort를 지원한다.
구조체 정렬
그렇다면 구조체를 정렬하기 위해서는 어떻게 해야할까? 다행히 공식 문서에 사용법에 대한 예제 코드가 존재한다.
// 정렬할 구조체다. Name과 Age 멤버변수가 있다.
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s: %d", p.Name, p.Age)
}
// Go의 sort.Sort()는 `func Sort(data Interface)`로 정의되어 있다.
// 따라서 커스텀타입을 정렬하기 위해서는 인터페이스가 필요하다.
// ByAge는 Age를 기준으로 정렬하기 위해 Person slice타입이다.
type ByAge []Person
// Sort Interface를 충족시키기 위한 Len(), Swap(int, int), Less(int, int)다.
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func main() {
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
fmt.Println(people)
// sort하는 방법에는 2가지가 있다.
// 첫번째는 slice타입의 인터페이스를 구현하고 sort.Sort로 정렬하는 방법이다.
sort.Sort(ByAge(people))
fmt.Println(people)
// 두번째 방법은 sort.Slice로 Less() 함수를 커스텀해서 구현하는 방법인데 closure를 사용하면 구현할 수 있다. 이 경우에는 slice타입의 인터페이스를 만족시키기 위해 메소드들을 구현할 필요가 없다.
// 여기서는 정렬된 people slice를 다시 뒤집어본다.
sort.Slice(people, func(i, j int) bool {
return people[i].Age > people[j].Age
})
fmt.Println(people)
}
/* output
[Bob: 31 John: 42 Michael: 17 Jenny: 26] // 정렬안된 데이터
[Michael: 17 Jenny: 26 Bob: 31 John: 42] // 정렬된 데이터
[John: 42 Bob: 31 Jenny: 26 Michael: 17] // 뒤집은 데이터
*/
전체코드
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s: %d", p.Name, p.Age)
}
// ByAge implements sort.Interface for []Person based on
// the Age field.
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func main() {
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
fmt.Println(people)
// There are two ways to sort a slice. First, one can define
// a set of methods for the slice type, as with ByAge, and
// call sort.Sort. In this first example we use that technique.
sort.Sort(ByAge(people))
fmt.Println(people)
// The other way is to use sort.Slice with a custom Less
// function, which can be provided as a closure. In this
// case no methods are needed. (And if they exist, they
// are ignored.) Here we re-sort in reverse order: compare
// the closure with ByAge.Less.
sort.Slice(people, func(i, j int) bool {
return people[i].Age > people[j].Age
})
fmt.Println(people)
}
반응형
map 정렬
map에 든 데이터를 정렬하는 일이 발생할 수 있다. map은 key와 value로 이루어져 있다.
우선 key based sort를 먼저 보자.
func main() {
// 아래에 string-int를 key-value로 갖는 map 데이터가 있고
person := map[string]int{
"cain": 25,
"bob": 19,
"alice": 21,
"dela": 22,
}
var names []string
// person을 순회하면서 key를 뽑아서 names 슬라이스에 저장한다.
for k, v := range person {
// v == person[k]
fmt.Printf("name:%s, age:%d is equal %d\n", k, v, person[k])
names = append(names, k)
}
fmt.Println("==============")
fmt.Println("key based sort")
// names를 정렬하고
sort.Strings(names)
// names를 순회하면서 name을 map에 넣으면 name의 순서대로 정렬이 된다.
for _, name := range names {
fmt.Printf("name:%s, age:%d\n", name, person[name])
}
위 방식은 정확히는 정렬이 된 데이터가 아니라 정렬이 될 데이터(names)로 뽑아내는 방법이다.
다음으로는 value based sort를 보자.
type Person struct {
age int
name string
}
func main() {
person := map[string]int{
"cain": 25,
"bob": 19,
"alice": 21,
"dela": 22,
}
var p []Person
// person을 순회하면서 Person 구조체를 갖고 있는 p에 value와 key를 넣어준다.
for k, v := range person {
p = append(p, Person{v, k})
}
fmt.Println("value based sort")
// slice인 Person을 정렬하기 위해 closure로 정렬했다.
sort.Slice(p, func(i, j int) bool {
return p[i].age < p[j].age
})
fmt.Println(p)
fmt.Println("==============")
}
key based sort와 다른점은 value based sort는 정렬할 데이터가 아니라 정렬된 데이터 를 갖게 된다.
전체코드는 아래와 같다.
//mapsort.go
package main
import (
"fmt"
"sort"
)
type Person struct {
age int
name string
}
func main() {
person := map[string]int{
"cain": 25,
"bob": 19,
"alice": 21,
"dela": 22,
}
var names []string
var p []Person
for k, v := range person {
// v == person[k]
fmt.Printf("name:%s, age:%d is equal %d\n", k, v, person[k])
names = append(names, k)
p = append(p, Person{v, k})
}
fmt.Println("==============")
fmt.Println("key based sort")
sort.Strings(names)
for _, name := range names {
fmt.Printf("name:%s, age:%d\n", name, person[name])
}
fmt.Println("==============")
fmt.Println("value based sort")
sort.Slice(p, func(i, j int) bool {
return p[i].age < p[j].age
})
fmt.Println(p)
fmt.Println("==============")
}
연습문제
프로그래머스의 https://programmers.co.kr/learn/courses/30/lessons/42579 문제를 Go로 풀면서 연습해보자. sort 인터페이스를 만족시키며 구현할 수 있겠지만 코드량을 줄이기 위해 closure로 구현하는 것을 권장한다.
반응형
'Programming > Go' 카테고리의 다른 글
[Go] package public/private access (0) | 2022.07.21 |
---|---|
AWS 도메인 연결과 Docker 컨테이너 통신 (0) | 2021.05.11 |
Go 서버 애플리케이션을 Docker로 AWS EC2에 배포 (0) | 2021.05.07 |
[Go] 패키지 네이밍(package naming) (0) | 2021.04.06 |
[Go] Go channel 데이터 파이프라인 (2) | 2021.04.05 |
Comments