Go言語での構造体スライスの活用とソート方法を徹底解説

Go言語において、構造体スライスはデータ管理と処理において強力な手法です。構造体スライスを適切に活用することで、複雑なデータを効率的に管理し、柔軟に操作できるようになります。また、ソート機能を駆使することで、特定の条件に基づいたデータの並び替えが可能になり、より実践的で応用性の高いプログラムを作成することができます。本記事では、構造体スライスの基本的な活用方法から、Go標準ライブラリを使用したソート、カスタムソート、さらに応用的なフィルタリングまでを徹底解説し、Goプログラミングにおけるデータ処理のスキル向上を目指します。

目次

構造体スライスの基本

Go言語では、構造体スライスを使用することで、同じ型の複数のデータを効率的に格納・管理できます。構造体スライスは、特に複数のフィールドを持つデータを一括で処理する場合に便利です。まず、構造体スライスを定義し、初期化する基本的な方法を見ていきます。

構造体の定義

構造体は複数のフィールドを持つデータ型です。以下は、Personという名前の構造体の例です。この構造体は、Name(名前)とAge(年齢)というフィールドを持ちます。

type Person struct {
    Name string
    Age  int
}

構造体スライスの定義と初期化

構造体スライスは、上記のような構造体を格納するためのスライスです。以下のように定義し、初期化することができます。

people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
}

上記の例では、3つのPerson構造体を含むスライスpeopleが初期化されています。

動的な要素の追加

構造体スライスには、append関数を使用して要素を動的に追加することができます。

newPerson := Person{Name: "David", Age: 40}
people = append(people, newPerson)

このようにして、構造体スライスに柔軟に要素を追加できるため、データの管理と操作が容易になります。次のセクションでは、スライスの基本操作をさらに詳しく見ていきましょう。

スライス操作の基礎

構造体スライスでは、さまざまな操作を行うことでデータの追加、削除、参照が柔軟に可能です。このセクションでは、構造体スライスの基本操作について詳しく説明します。

要素の追加

Goでは、append関数を使って構造体スライスに新しい要素を追加することができます。append関数は、スライスの末尾に新しい要素を加えた新しいスライスを返します。

newPerson := Person{Name: "Eve", Age: 28}
people = append(people, newPerson)

このコードにより、スライスpeopleの末尾にnewPersonが追加されます。

要素の削除

Goでは、特定のインデックスにある要素を削除するために、スライスの一部を切り出して再代入する方法を用います。たとえば、インデックス1の要素を削除する場合、以下のようにします。

people = append(people[:1], people[2:]...)

このコードは、スライスの先頭から1番目までと、2番目以降を結合し、1番目の要素をスライスから除外します。

要素の参照

構造体スライスの特定の要素を参照するには、インデックスを指定します。

fmt.Println(people[0].Name) // "Alice"と表示されます

スライス内の要素をループ処理で一括して処理することも可能です。以下はforループでpeopleスライスの各要素を出力する例です。

for _, person := range people {
    fmt.Println(person.Name, person.Age)
}

スライスの長さと容量

Goでは、スライスの長さをlen関数で、容量をcap関数で取得できます。長さは現在の要素数、容量は内部配列のサイズを指します。

fmt.Println(len(people)) // スライスの長さ
fmt.Println(cap(people)) // スライスの容量

構造体スライスの基本操作を理解することで、データの追加・削除・参照が容易になり、Goプログラムの柔軟性が向上します。次は、構造体スライスを使ったソートの必要性とそのユースケースについて説明します。

ソートの重要性とユースケース

構造体スライスのソートは、特定の条件に基づいたデータの整列に役立ち、データの検索や表示、分析を効率的に行えるようにする重要な手法です。このセクションでは、構造体スライスのソートが必要になる場面と、一般的なユースケースについて解説します。

データの検索や可視化の向上

データがソートされていると、検索や表示がスムーズに行えます。例えば、年齢や名前のアルファベット順でソートされたリストは、ユーザーインターフェース上で見やすく、必要な情報を迅速に見つけやすくなります。

例: 人のリストを年齢順に並べる

例えば、Person構造体のリストを年齢順にソートすることで、最年少から最年長の順にデータを参照できます。これは、特定の年齢層を対象にした分析やフィルタリングにも有効です。

データ分析の効率化

データをあらかじめソートしておくと、統計分析やグラフ作成などのデータ処理が効率化されます。たとえば、構造体スライスを価格やスコアなどの数値順にソートしておくことで、最小・最大の値や中央値を容易に取得できるため、レポートや分析が簡単になります。

例: 商品のリストを価格順にソート

商品のリストを価格順に並べ替え、最も安い商品や最も高い商品を確認することで、価格帯に応じたマーケティング戦略や購入分析が可能になります。

カスタムソートが必要なケース

多くのユースケースでは、単純な昇順や降順の並び替えではなく、カスタム基準に基づくソートが求められます。例えば、Person構造体で「年齢が若い順、ただし同年齢であれば名前のアルファベット順」といった複合的な基準を設けてソートするケースもあります。

このように、構造体スライスを使ったソートは、データの可視化、検索、分析の効果を高め、プログラムの実用性を大幅に向上させます。次のセクションでは、Goの標準ライブラリsortパッケージを使ったソート方法を見ていきましょう。

sortパッケージの活用方法

Go言語では、標準ライブラリのsortパッケージを使用してスライスのソートを効率的に行うことができます。sortパッケージには、基本的なソート関数が用意されており、特定の条件に基づくカスタムソートも可能です。ここでは、構造体スライスをソートするためのsortパッケージの基本的な使い方を解説します。

基本的なソート

sortパッケージには、整数スライスや文字列スライスを昇順でソートするための関数が用意されています。しかし、構造体スライスをソートするためには、独自のソート基準を定義する必要があります。Goのsort.Slice関数を使うと、構造体のフィールドに基づいてスライスを簡単に並び替えることが可能です。

例: 年齢で昇順にソートする

次の例では、Person構造体スライスを年齢順にソートしています。

type Person struct {
    Name string
    Age  int
}

people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
}

// 年齢で昇順にソート
sort.Slice(people, func(i, j int) bool {
    return people[i].Age < people[j].Age
})

このコードは、peopleスライスを年齢に基づいて昇順にソートします。sort.Slice関数の第2引数には、ソート基準を定義する関数を指定します。この関数は、比較対象となるインデックスijを受け取り、trueを返すとijの前に配置されます。

降順でのソート

降順にソートする場合は、比較演算子を逆にします。例えば、年齢が高い順に並べ替えるには、次のようにします。

sort.Slice(people, func(i, j int) bool {
    return people[i].Age > people[j].Age
})

このコードでは、年齢が高い順にpeopleスライスがソートされます。

文字列フィールドでのソート

構造体の文字列フィールド(例えば、名前)でソートする場合も同様に、ソート条件として文字列の比較を行います。

sort.Slice(people, func(i, j int) bool {
    return people[i].Name < people[j].Name
})

このコードは、Nameフィールドをアルファベット順で並べ替えます。

複合条件でのソート

複数のフィールドを基準にしたソートも可能です。例えば、年齢順で並べ、同じ年齢の場合は名前でソートする場合は、次のように記述します。

sort.Slice(people, func(i, j int) bool {
    if people[i].Age == people[j].Age {
        return people[i].Name < people[j].Name
    }
    return people[i].Age < people[j].Age
})

このように、sortパッケージを活用することで、構造体スライスを柔軟かつ効率的にソートできます。次は、カスタムソートの詳細な実装についてさらに深掘りしていきます。

カスタムソートの実装

Go言語では、特定の条件に基づいて構造体スライスをカスタムソートするために、sort.Interfaceを実装する方法があります。sort.Slice関数でもカスタムソートができますが、複雑な条件がある場合やコードの再利用性を高めたい場合には、sort.Interfaceを実装する方法が役立ちます。ここでは、構造体フィールドを基準としたカスタムソートの具体的な手順を解説します。

sort.Interfaceの要件

sort.Interfaceを実装するには、以下の3つのメソッドを構造体スライスに対して実装する必要があります。

  1. Len() int:スライスの長さを返します。
  2. Less(i, j int) booli番目の要素がj番目の要素より小さい場合にtrueを返します。
  3. Swap(i, j int)i番目とj番目の要素を入れ替えます。

これらのメソッドを実装することで、Goの標準ソート機能を使ってカスタム条件で並び替えができるようになります。

例: 年齢と名前でカスタムソート

ここでは、Person構造体を持つスライスPeopleを作成し、年齢順、同じ年齢なら名前順でソートするカスタムソートを実装します。

package main

import (
    "fmt"
    "sort"
)

type Person struct {
    Name string
    Age  int
}

type People []Person

// Lenメソッド
func (p People) Len() int {
    return len(p)
}

// Lessメソッド
func (p People) Less(i, j int) bool {
    if p[i].Age == p[j].Age {
        return p[i].Name < p[j].Name // 名前で比較
    }
    return p[i].Age < p[j].Age // 年齢で比較
}

// Swapメソッド
func (p People) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
}

上記のコードでは、People型に対してLenLessSwapメソッドが実装されているため、Peoplesort.Interfaceを満たします。このようにすることで、標準ライブラリのsort.Sort関数を使ってソートを実行できるようになります。

ソートの実行

sort.Sortを用いて、定義したカスタムソートを実行します。

func main() {
    people := People{
        {Name: "Alice", Age: 30},
        {Name: "Bob", Age: 25},
        {Name: "Charlie", Age: 30},
        {Name: "Dave", Age: 25},
    }

    sort.Sort(people)

    for _, person := range people {
        fmt.Println(person.Name, person.Age)
    }
}

このコードを実行すると、まず年齢順にソートされ、同じ年齢の人々は名前のアルファベット順に並べ替えられた結果が得られます。出力例は以下のようになります。

Bob 25
Dave 25
Alice 30
Charlie 30

応用:降順でのカスタムソート

昇順ではなく降順でソートしたい場合は、Lessメソッド内の条件を反転させることで実現できます。また、sort.Reverseを使用して、簡単に逆順にすることも可能です。

sort.Sort(sort.Reverse(people))

カスタムソートを実装することで、柔軟なデータ操作が可能となり、Goプログラムにおけるデータの整列や処理の幅が広がります。次のセクションでは、構造体スライスのソートだけでなく、条件に基づくフィルタリング方法について解説します。

ソートに必要なインターフェースの実装

構造体スライスをGoの標準ソート機能でソートするためには、sort.Interfaceを実装する必要があります。このインターフェースは、3つのメソッド—LenSwapLess—で構成されており、これらを実装することで、構造体の特定フィールドを基準としたカスタムソートが可能になります。ここでは、それぞれのメソッドの役割と実装方法を詳しく解説します。

1. Lenメソッド

Lenメソッドは、スライスの要素数を返す必要があります。これはソートの範囲を知るために使用されるため、構造体スライスの長さを返すように実装します。

func (p People) Len() int {
    return len(p)
}

このように、Peopleスライスの長さを返すシンプルなメソッドです。これにより、sortパッケージはスライスの範囲を把握できるようになります。

2. Swapメソッド

Swapメソッドは、スライス内の2つの要素を入れ替えます。このメソッドは、ソート処理の途中で要素を並べ替えるために必要です。

func (p People) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
}

ここでは、インデックスijの位置にある要素を入れ替えています。これにより、ソートアルゴリズムが指定された基準に基づいて要素を並べ替えられるようになります。

3. Lessメソッド

Lessメソッドは、要素iが要素jよりも「小さい」場合にtrueを返します。このメソッドを使って、ソートの基準を定義します。

例: 年齢順にソート

たとえば、Person構造体のAgeフィールドを基準に昇順でソートしたい場合、次のようにLessメソッドを実装します。

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

このコードにより、年齢が小さい順に並び替えられます。

複合条件でのソート

複数の条件でソートしたい場合、Lessメソッド内で条件を追加することができます。例えば、同じ年齢であれば名前のアルファベット順にソートする場合、次のように記述します。

func (p People) Less(i, j int) bool {
    if p[i].Age == p[j].Age {
        return p[i].Name < p[j].Name
    }
    return p[i].Age < p[j].Age
}

これにより、Ageが同じ場合はNameで比較される複合条件のソートが実現できます。

インターフェースの実装によるソートの実行

これらのメソッドを実装することで、sort.Sortを使ってPeopleスライスをカスタムソートできるようになります。

people := People{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 30},
    {Name: "Dave", Age: 25},
}

sort.Sort(people)

このようにsort.Sortを呼び出すことで、定義したカスタム基準に基づいたソートが実行されます。ソートインターフェースを実装することで、柔軟なソート条件に対応でき、Goプログラムにおけるデータ処理が大幅に効率化されます。

次のセクションでは、ソートだけでなく、構造体スライスに対する条件付きフィルタリングについて紹介します。

スライス内の条件付きフィルタリング

ソートだけでなく、構造体スライスのデータを特定の条件に基づいてフィルタリングすることで、必要な情報だけを効率的に抽出することができます。フィルタリングは、特定の条件に合致する要素のみを処理したい場合や、不要なデータを除外したい場合に非常に有効です。ここでは、構造体スライスに対する条件付きフィルタリングの方法と実装例を解説します。

フィルタリングの基本

構造体スライスをフィルタリングする場合、一般的には新しいスライスを作成し、条件に合致する要素のみを追加する方法をとります。Go言語ではappend関数を利用して新しいスライスに条件に合った要素だけを追加することで、フィルタリングが可能です。

例: 特定の年齢以上の人物を抽出

以下の例では、年齢が30以上のPersonのみを抽出して新しいスライスを作成します。

type Person struct {
    Name string
    Age  int
}

func filterByAge(people []Person, minAge int) []Person {
    var filtered []Person
    for _, person := range people {
        if person.Age >= minAge {
            filtered = append(filtered, person)
        }
    }
    return filtered
}

このコードでは、filterByAge関数がスライスpeople内で年齢がminAge以上のPersonのみを含む新しいスライスfilteredを返します。

使用例

people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
}

filteredPeople := filterByAge(people, 30)
for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

このコードを実行すると、年齢が30以上の人物のみが出力されます。

複数条件でのフィルタリング

フィルタリング条件は1つに限らず、複数の条件を組み合わせることも可能です。例えば、年齢が30以上かつ名前が”A”から始まる人物を抽出したい場合、次のように条件を追加します。

func filterByAgeAndName(people []Person, minAge int, prefix string) []Person {
    var filtered []Person
    for _, person := range people {
        if person.Age >= minAge && strings.HasPrefix(person.Name, prefix) {
            filtered = append(filtered, person)
        }
    }
    return filtered
}

このfilterByAgeAndName関数では、年齢がminAge以上で、かつ名前が指定した文字列prefixで始まる人物のみがfilteredスライスに追加されます。

使用例

filteredPeople := filterByAgeAndName(people, 30, "A")
for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

この例では、Aliceが出力され、他の条件に合致しない人物は除外されます。

匿名関数を使った柔軟なフィルタリング

より柔軟に条件を変えたい場合は、フィルタリングの条件を匿名関数として渡すこともできます。以下は、条件を関数パラメータとして受け取る汎用的なフィルタ関数の例です。

func filter(people []Person, test func(Person) bool) []Person {
    var filtered []Person
    for _, person := range people {
        if test(person) {
            filtered = append(filtered, person)
        }
    }
    return filtered
}

このfilter関数を使うことで、任意の条件を柔軟に設定してフィルタリングが可能です。

使用例

filteredPeople := filter(people, func(p Person) bool {
    return p.Age >= 30 && strings.HasPrefix(p.Name, "A")
})
for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

このコードにより、カスタマイズされたフィルタリング条件を実行できます。匿名関数を使用することで、条件を自由に指定できるため、さまざまな用途に対応できます。

条件付きフィルタリングにより、構造体スライス内の特定データだけを効率的に抽出できるため、データ処理の柔軟性と精度が向上します。次のセクションでは、さらに高度な応用例として、複数条件のソートとフィルタリングの組み合わせを見ていきましょう。

応用例:複雑な条件でのソートとフィルタリング

実務では、データを複数の条件に基づいて並び替えたり、抽出したりする必要がしばしば発生します。Go言語では、カスタムソートと条件付きフィルタリングを組み合わせて、複雑なデータ操作が可能です。このセクションでは、複数の条件を使ったソートとフィルタリングの複合的な応用例を紹介します。

複数条件によるソート

複数の条件でソートする場合、まず優先度の高い条件を定義し、それに該当しない場合に次の条件で比較する形でLessメソッドを設計します。以下では、年齢順にソートし、同じ年齢の場合は名前のアルファベット順に並べる例を示します。

type Person struct {
    Name string
    Age  int
}

type People []Person

func (p People) Len() int           { return len(p) }
func (p People) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p People) Less(i, j int) bool {
    if p[i].Age == p[j].Age {
        return p[i].Name < p[j].Name // 名前のアルファベット順
    }
    return p[i].Age < p[j].Age // 年齢順
}

このコードでは、まず年齢で比較し、年齢が同じ場合は名前で並べ替えます。次に、sort.Sortを使ってPeopleスライスを並べ替えることができます。

使用例

people := People{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 30},
    {Name: "Dave", Age: 25},
}

sort.Sort(people)
for _, person := range people {
    fmt.Println(person.Name, person.Age)
}

出力結果は以下の通りです。

Bob 25
Dave 25
Alice 30
Charlie 30

これにより、年齢順で、同じ年齢の場合は名前順で整列された結果が得られます。

ソートとフィルタリングの組み合わせ

フィルタリングとソートを組み合わせることで、例えば「年齢が30以上の人を抽出し、名前順で並べ替える」といった処理が実現可能です。まずフィルタリングで必要なデータのみを抽出し、その後にソートを適用します。

例: 年齢30以上の人を名前順でソート

まず、年齢が30以上の人を抽出し、それを名前順にソートするコードを示します。

func filterByMinAge(people []Person, minAge int) []Person {
    var filtered []Person
    for _, person := range people {
        if person.Age >= minAge {
            filtered = append(filtered, person)
        }
    }
    return filtered
}

type ByName []Person

func (n ByName) Len() int           { return len(n) }
func (n ByName) Swap(i, j int)      { n[i], n[j] = n[j], n[i] }
func (n ByName) Less(i, j int) bool { return n[i].Name < n[j].Name }

次に、フィルタリング関数とソートを組み合わせて実行します。

people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
    {Name: "Dave", Age: 32},
}

filteredPeople := filterByMinAge(people, 30)
sort.Sort(ByName(filteredPeople))

for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

このコードを実行すると、年齢が30以上の人物のみが名前順で出力されます。

Alice 30
Charlie 35
Dave 32

匿名関数を使った柔軟なフィルタリングとソート

匿名関数を用いて、より柔軟なフィルタリングとソート条件を設定することも可能です。匿名関数はフィルタリング関数に直接条件を渡すため、変更が簡単でコードの再利用性が高まります。

func filter(people []Person, test func(Person) bool) []Person {
    var filtered []Person
    for _, person := range people {
        if test(person) {
            filtered = append(filtered, person)
        }
    }
    return filtered
}

たとえば、「年齢が30以上かつ名前が"A"で始まる人」を抽出する場合、以下のように匿名関数を利用します。

filteredPeople := filter(people, func(p Person) bool {
    return p.Age >= 30 && strings.HasPrefix(p.Name, "A")
})

これにより、柔軟にフィルタリング条件を変更できるため、さまざまなシナリオに対応した複雑なデータ処理が可能になります。

このように、Go言語での複雑な条件でのソートとフィルタリングを組み合わせることで、データを効率的に整理・活用するスキルが向上します。次のセクションでは、構造体スライスを使用した効率的なデータ処理のためのポイントについて紹介します。

効率的なデータ処理のためのポイント

構造体スライスを使ったデータ処理は、適切に実装することでパフォーマンスを大幅に向上させることができます。特に、大量のデータを扱う場合、効率を考慮したコードを書くことが重要です。ここでは、構造体スライスを使った効率的なデータ処理のためのいくつかのポイントを解説します。

1. メモリ割り当ての最適化

スライスに新しい要素を追加する際、容量が不足するとGoは内部で新しいメモリ領域を確保し、既存のデータをコピーする処理が発生します。頻繁なメモリ再割り当てを避けるために、スライスの容量を事前に見積もり、make関数で適切な初期容量を確保すると良いでしょう。

people := make([]Person, 0, 100) // 100人分の容量を確保

これにより、スライスが容量を超えない限りメモリ再割り当てが発生せず、パフォーマンスが向上します。

2. 並列処理の活用

大量のデータ処理が必要な場合、並列処理を活用することで処理速度を向上させることができます。Goのgoroutineを利用して、スライス内のデータを並行して処理することで、複数のCPUコアを効率的に活用できます。

var wg sync.WaitGroup
for i := 0; i < len(people); i++ {
    wg.Add(1)
    go func(p Person) {
        defer wg.Done()
        // 個々のデータ処理
        fmt.Println(p.Name, p.Age)
    }(people[i])
}
wg.Wait()

このコードでは、goroutineを使って個々の要素を並行処理しています。sync.WaitGroupを利用することで、すべての並列処理が完了するまで待機できます。

3. 条件付き処理をフィルタリングで効率化

条件付きのデータ処理を行う際には、まずフィルタリングで必要な要素のみを抽出してから処理を行うと、無駄な演算を減らし、効率的な処理が可能になります。フィルタリング後のスライスを使って必要な処理を行うようにしましょう。

filteredPeople := filter(people, func(p Person) bool {
    return p.Age >= 30
})
for _, person := range filteredPeople {
    // フィルタリング後の処理
    fmt.Println(person.Name, person.Age)
}

4. 再利用可能な関数の設計

データ処理におけるフィルタリングやソートの関数を汎用的に設計することで、異なる条件の処理にも対応できるようになります。特に、匿名関数を活用して条件を柔軟に変更できるように設計することで、コードの再利用性が向上します。

5. プロファイリングでパフォーマンスを測定する

パフォーマンス改善には、まずボトルネックを特定することが重要です。Goのプロファイリングツールpprofを使用することで、処理時間やメモリ使用量を測定し、効率化の対象となる箇所を特定できます。

import (
    "log"
    "net/http"
    _ "net/http/pprof"
)

func main() {
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()
    // メイン処理
}

実行中にブラウザでhttp://localhost:6060/debug/pprof/にアクセスすることで、パフォーマンスの測定データを確認できます。


これらのポイントを意識することで、Go言語での構造体スライスのデータ処理がさらに効率化され、パフォーマンスの向上が期待できます。次のセクションでは、理解を深めるための演習問題とその解答例を紹介します。

演習問題と実践例

ここでは、構造体スライスの活用方法やカスタムソート、条件付きフィルタリングを実際に試せる演習問題と、その解答例を紹介します。これらの演習を通じて、Go言語でのデータ処理の理解を深めましょう。

演習問題1: 年齢の範囲でフィルタリング

問題: Person構造体スライスから、年齢が25歳から35歳の範囲にある人物のみを抽出し、年齢の昇順でソートして出力してください。

// 構造体とデータの定義
type Person struct {
    Name string
    Age  int
}

people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
    {Name: "Dave", Age: 20},
    {Name: "Eve", Age: 28},
}

// 解答例
filteredPeople := filter(people, func(p Person) bool {
    return p.Age >= 25 && p.Age <= 35
})
sort.Slice(filteredPeople, func(i, j int) bool {
    return filteredPeople[i].Age < filteredPeople[j].Age
})

for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

期待される出力例:

Bob 25
Eve 28
Alice 30
Charlie 35

演習問題2: 複合条件によるフィルタリングとソート

問題: 年齢が30以上かつ名前が”A”で始まる人物のみを抽出し、年齢の降順でソートして出力してください。

// 解答例
filteredPeople := filter(people, func(p Person) bool {
    return p.Age >= 30 && strings.HasPrefix(p.Name, "A")
})
sort.Slice(filteredPeople, func(i, j int) bool {
    return filteredPeople[i].Age > filteredPeople[j].Age
})

for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

期待される出力例:

Alice 30

演習問題3: インターフェースによるカスタムソート

問題: 名前がアルファベット順になるように、sort.Interfaceを実装して構造体スライスを並び替えてください。

// インターフェースの実装
type ByName []Person

func (n ByName) Len() int           { return len(n) }
func (n ByName) Swap(i, j int)      { n[i], n[j] = n[j], n[i] }
func (n ByName) Less(i, j int) bool { return n[i].Name < n[j].Name }

// ソート実行
peopleByName := ByName(people)
sort.Sort(peopleByName)

for _, person := range peopleByName {
    fmt.Println(person.Name, person.Age)
}

期待される出力例:

Alice 30
Bob 25
Charlie 35
Dave 20
Eve 28

演習問題4: Goroutineを使った並列データ処理

問題: 各人物の名前と年齢を並列に出力するgoroutineを使ったプログラムを作成してください。

var wg sync.WaitGroup
for _, person := range people {
    wg.Add(1)
    go func(p Person) {
        defer wg.Done()
        fmt.Println(p.Name, p.Age)
    }(person)
}
wg.Wait()

期待される出力例: (順不同で、各人物の名前と年齢が並列に出力されます)

Alice 30
Bob 25
Charlie 35
Dave 20
Eve 28

演習問題5: 名前の長さでフィルタリングとソート

問題: 名前の長さが3文字以下の人物のみを抽出し、名前の長さの昇順でソートしてください。

// 解答例
filteredPeople := filter(people, func(p Person) bool {
    return len(p.Name) <= 3
})
sort.Slice(filteredPeople, func(i, j int) bool {
    return len(filteredPeople[i].Name) < len(filteredPeople[j].Name)
})

for _, person := range filteredPeople {
    fmt.Println(person.Name, person.Age)
}

期待される出力例: (3文字以下の名前順)

Bob 25
Eve 28

これらの演習を通じて、Go言語での構造体スライスの活用方法、カスタムソート、条件付きフィルタリング、並列処理についての理解が深まるはずです。次のセクションでは、記事の内容をまとめて振り返ります。

まとめ

本記事では、Go言語における構造体スライスの基本操作から、カスタムソートや条件付きフィルタリング、並列処理までの活用方法を解説しました。構造体スライスを適切に操作することで、複雑なデータを整理・管理しやすくなり、パフォーマンスの向上も期待できます。また、sort.Interfaceの実装によるカスタムソートや、匿名関数を使った柔軟なフィルタリング、goroutineによる並列処理により、Goでのデータ処理がさらに強力になりました。

構造体スライスとソート・フィルタリングの応用は、さまざまなデータ処理シナリオで役立ちます。今回の内容を実践することで、Goプログラムにおけるデータ処理の効率化と柔軟性をさらに高めていきましょう。

コメント

コメントする

目次