go

Go에서 컬렉션 정렬하는 방법 (Go Sort)

1. 들어가며

Go에서는 여러 컬렉션 타입에 대해서 어떻게 정렬할 수 있는지에 대해서 알아보자.

  • Primitive 데이터 타입 정렬하기
  • Custom comparator로 정렬하기
  • Sort interface로 정렬하기
  • Map에서 특정 key/value로 정렬하기

2.Sort 4가지 방법

2.1 Primitive 데이터 타입 정렬하기

Primitive 데이터 타입에 대해서는 아래 함수들을 제공해주고 있다.

  • sort.Ints
  • sort.Float64
  • sort.Strings
func Example_Sort_Int_Primitive_Type() {
	list := []int{4, 2, 3, 1}
	sort.Ints(list)
	fmt.Println(list)

	//Output:
	// [1 2 3 4]
}

func Example_Sort_String_Primitive_Type() {
	list := []string{"d", "f", "a", "y", "e"}
	sort.Strings(list)
	fmt.Println(list)

	//Output:
	// [a d e f y]
}

2.2 Struct 구조체 정렬하기

사용자 정의 Comparator 함수를 정의해서 구조체의 속성값 기준으로 정렬할 수 있다. 아래는 Employee의 나이 적은 순으로 정렬한 예제이다.

func Example_Sort_Struct_With_Custom_Comparator() {
	employee := []struct {
		Name string
		Age  int
	}{
		{"Alice", 23},
		{"David", 2},
		{"Eve", 2},
		{"Bob", 25},
	}

	// Sort by age, keeping original order or equal elements.
	sort.SliceStable(employee, func(i, j int) bool {
		return employee[i].Age < employee[j].Age
	})
	fmt.Println(employee)

	//Output:
	//[{David 2} {Eve 2} {Alice 23} {Bob 25}]
}

2.3 정렬 인터페이스로 구조체 정렬하기

정렬 인터페이스로도 구조체를 정렬할 수 있다. sort.Sort() 메서드는 sort.Interface 정렬 인터페이스를 인자로 받는다. 정렬 인터페이스는 아래 3가지 Len(), Less(), Swap() 메서드를 구현하면 해당 구조체를 정렬할 수 있다.

func Sort(data Interface) {
	n := data.Len()
	quickSort(data, 0, n, maxDepth(n))
}

type Interface interface {
	// Len is the number of elements in the collection.
	Len() int
	// Less reports whether the element with
	// index i should sort before the element with index j.
	Less(i, j int) bool
	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

먼저 Age 순으로 정렬하기 위해 ByAge type을 정의한다. 그리고 정의한 타입에 대해서 위 3가지 메서드를 구현한다.

type Employee struct {
	Name string
	Age  int
}

// ByAge implements sort.Interface based on the Age field.
type ByAge []Employee

func (a ByAge) Len() int {
	return len(a)
}

func (a ByAge) Less(i, j int) bool {
	return a[i].Age < a[j].Age
}

func (a ByAge) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

sort.Sort() 메서드 인자에 family 배열 구조체를 model.ByAge 타입 변환해서 정렬시킨다.

func Example_Sort_Any_Collection_By_Implementing_Sort_Interface() {
	family := []model.Employee{
		{"Alice", 23},
		{"Eve", 2},
		{"Bob", 25},
	}
	sort.Sort(model.ByAge(family))
	fmt.Println(family)
	//Output:
	//[{Eve 2} {Alice 23} {Bob 25}]
}

2.4 Map 의 특정 key나 value 값으로 정렬하기

마지막으로 Map 데이터에서 특정 key나 value 값으로 정렬하는 방법에 대해서 알아보자. 아래 예제에서는 map에서 key 값만 먼저 정렬시킨 후 정렬된 key 값으로 map에서 가져오면 특정 key 값으로 정렬할 수 있다.

func Example_Sort_Map_By_Key_or_Value() {
	m := map[string]int{
		"Alice": 2,
		"Cecil": 1,
		"Bob":   3,
	}

	sortKeys := make([]string, 0, len(m))

	for k := range m {
		fmt.Println("k", k)
		sortKeys = append(sortKeys, k)
	}
	sort.Strings(sortKeys) //keys로 정렬을 함

	//정렬한 keys 값으로 데이터를 출력함
	for _, k := range sortKeys {
		fmt.Println(k, m[k])
	}

	//Output:
	//Alice 2
	//Bob 3
	//Cecil 1
}

3. 마무리

다양한 방법으로 여러 데이터 타입 배열을 정렬해보았다. 여기서 작성한 코드는 github에서 확인할 수 있다.

4. 참고