정렬 활용하기

이재홍 http://www.pyrasis.com 2014.12.17 ~ 2015.02.07

정렬 인터페이스를 이용하여 구조체 정렬하기

다음은 정렬 인터페이스의 정의입니다.

type Interface interface {
	Len() int           // 데이터의 길이를 구함
	Less(i, j int) bool // 대소관계를 판단. i가 작으면 true를 리턴하도록 구현
	Swap(i, j int)      // Less 메서드에서 true가 나오면 두 데이터의 위치를 바꿈
}
메서드 설명
Len 데이터의 개수(길이)를 구합니다.
Less 대소관계를 판단합니다. 두 데이터 i, j를 받은 뒤 i가 작으면 true를 리턴하도록 구현합니다.
Swap Less 메서드에서 true가 나오면 두 데이터의 위치를 바꿉니다.

표 54-2 sort.Interface의 메서드

이제 정렬 인터페이스를 구현하여 구조체가 담긴 슬라이스를 정렬해보겠습니다. 다음은 학생을 이름순, 점수순으로 정렬합니다.

package main

import (
	"fmt"
	"sort"
)

type Student struct {
	name  string
	score float32
}

type Students []Student

func (s Students) Len() int {
	return len(s) // 데이터의 길이를 구함. 슬라이스이므로 len 함수를 사용
}

func (s Students) Less(i, j int) bool {
	return s[i].name < s[j].name // 학생 이름순으로 정렬
}

func (s Students) Swap(i, j int) {
	s[i], s[j] = s[j], s[i] // 두 데이터의 위치를 바꿈
}

type ByScore struct { // 점수순 정렬을 위해 구조체 정의
	Students
}

func (s ByScore) Less(i, j int) bool {
	return s.Students[i].score < s.Students[j].score // 학생 점수순으로 정렬
}

func main() {
	s := Students{
		{"Maria", 89.3},
		{"Andrew", 72.6},
		{"John", 93.1},
	}

	sort.Sort(s) // 이름을 기준으로 오름차순 정렬
	fmt.Println(s)

	sort.Sort(sort.Reverse(ByScore{s})) // 점수를 기존으로 내림차순 정렬
	fmt.Println(s)
}

실행 결과

[{Andrew 72.6} {John 93.1} {Maria 89.3}]
[{John 93.1} {Maria 89.3} {Andrew 72.6}]

학생의 이름과 점수를 저장하는 구조체를 정의하고, 학생을 저장하는 슬라이스도 정의합니다.

type Student struct {
	name  string
	score float32
}

type Students []Student

이제 Students 슬라이스를 정렬하려면 Studentssort.Interface를 구현해야 합니다. 따라서 sort.Interface는 다음과 같이 Len, Less, Swap 메서드를 만족해야합니다.

func (s Students) Len() int {
	return len(s) // 데이터의 길이를 구함. 슬라이스이므로 len 함수를 사용
}

func (s Students) Less(i, j int) bool {
	return s[i].name < s[j].name // 학생 이름순으로 정렬
}

func (s Students) Swap(i, j int) {
	s[i], s[j] = s[j], s[i] // 두 데이터의 위치를 바꿈
}

Students 타입의 Less 메서드는 학생 이름을 기준으로 정렬하도록 구현했습니다. 점수를 기준으로 정렬하려면 다음과 같이 구조체와 Less 메서드를 정의합니다.

type ByScore struct { // 점수순 정렬을 위해 구조체 정의
	Students
}

func (s ByScore) Less(i, j int) bool {
	return s.Students[i].score < s.Students[j].score // 학생 점수순으로 정렬
}

ByScore 구조체에는 Students 타입을 포함시켰습니다. 따라서 Students 타입에서 구현했던 Len, Less, Swap 메서드를 그대로 따릅니다. 하지만 점수를 기준으로 정렬해야 하므로 ByScore 구조체에서 Less 메서드를 다시 구현합니다. 즉, Go 언어에서는 이런 방식으로 상속(확장)을 구현합니다.

이제 학생 데이터를 준비한 뒤 이름순, 점수순(내림차순)으로 정렬합니다.

s := Students{
	{"Maria", 89.3},
	{"Andrew", 72.6},
	{"John", 93.1},
}

sort.Sort(s) // 이름을 기준으로 오름차순 정렬
fmt.Println(s)

sort.Sort(sort.Reverse(ByScore{s})) // 점수를 기존으로 내림차순 정렬
fmt.Println(s)

Students 타입은 sort.Interface를 구현했으므로 sort.Sort 함수에 그대로 넣을 수 있습니다. 그리고 점수순으로 정렬하려면 슬라이스를 ByScore 타입으로 다시 초기화해줍니다. 이렇게 하면 이름순으로 정렬하는 Students 타입의 Less 메서드를 사용하지 않고, 점수순으로 정렬하는 ByScore 타입의 Less 메서드를 사용하게 됩니다. 즉, 데이터를 둘러싸는 타입을 바꿔주면서 기능(메서드)을 바꾸는 방식입니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

01 June 2015