検索

Go言語でのソート説明

Jan 16, 2020 pm 05:30 PM
言語を移動

Go言語でのソート説明

#go 言語 の並べ替えの考え方は、c や c とは多少異なります。 c はデフォルトで配列をソートし、c はシーケンスをソートし、go はより一般的です。ソートされるオブジェクトは任意のオブジェクトですが、多くの場合、それはスライス (配列に似たスライス) であるか、またはスライスが含まれています。オブジェクト。

ソートの 3 つの要素 (インターフェース):

ソートする要素の数 n;

i 番目と j 番目の要素の比較関数 cmp;

i 番目と j 番目の要素の交換スワップ;

一見すると、条件 3 は冗長であり、c も c もスワップを提供しません。 C での qsort の使用法: qsort(data, n, sizeof(int), cmp_int); data は開始アドレス、n は要素の数、sizeof(int) は各要素のサイズ、cmp_int は次の比較です。 two ints 関数。

c sort の使用法: sort(data, data n, cmp_int); data は最初の要素の位置、data n は最後の要素の次の位置、cmp_int は比較関数です。

基本型 int、float64、string の並べ替え

昇順並べ替え

int の場合、 float64 および string 配列またはスライスをソートするために、go は、sort.Ints()、sort.Float64s()、sort.Strings() 関数をそれぞれ提供しており、デフォルトでは、小さいものから大きいものへソートされます。 (sort.Float32s() 関数はありません。これは私にとって少し奇妙です。)

package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    intList := [] int {2, 4, 3, 5, 7, 6, 9, 8, 1, 0}
    float8List := [] float64 {4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
    // float4List := [] float32 {4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}    // no function : sort.Float32s
    stringList := [] string {"a", "c", "b", "d", "f", "i", "z", "x", "w", "y"}
   
    sort.Ints(intList)
    sort.Float64s(float8List)
    sort.Strings(stringList)
   
    fmt.Printf("%v\n%v\n%v\n", intList, float8List, stringList)
 
}

降順ソート

int、float64、および string はすべてデフォルトの昇順を持ちます。ソート関数、ここで問題は、順序が降順の場合はどうなるかということです。他の言語でのプログラミング経験がある人なら誰でも、cmp の比較ルールを交換するだけでよいことを知っていますが、go の実装は似ていますが、異なります。

Go で特定の Type のオブジェクト obj を並べ替えるには、sort.Sort(obj) を使用できます。これは、3 つのメソッドを Type 型にバインドする必要があることを意味します: 長さを見つけるには Len()、Less (i,j) は i 番目と j 番目の要素の大きさを比較する関数、Swap(i,j) は i 番目と j 番目の要素を入れ替える関数です。

sort パッケージの 3 つのタイプ IntSlice、Float64Slice、および StringSlice は、これら 3 つのメソッドをそれぞれ実装しており、対応する並べ替えメソッドは [] int、[] float64、および [] string です。逆順に並べ替えたい場合は、対応する Less 関数を変更するだけです。

Go のsortパッケージでは、比較関数であるslice.Interface.Lessの代わりにsort.Reverse(slice)を使用できるため、int、float64、stringの逆ソート関数は次のように記述できます:

package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    intList := [] int {2, 4, 3, 5, 7, 6, 9, 8, 1, 0}
    float8List := [] float64 {4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
    stringList := [] string {"a", "c", "b", "d", "f", "i", "z", "x", "w", "y"}
   
    sort.Sort(sort.Reverse(sort.IntSlice(intList)))
    sort.Sort(sort.Reverse(sort.Float64Slice(float8List)))
    sort.Sort(sort.Reverse(sort.StringSlice(stringList)))
   
    fmt.Printf("%v\n%v\n%v\n", intList, float8List, stringList)
}

ソートの深い理解

sort パッケージには sort.Interface インターフェイスがあり、これには 3 つのメソッド Len()、Less(i,j) があります。および Swap(i,j) 。一般的な並べ替え関数 sort.Sort は、sort.Inferface インターフェイスを実装する任意のオブジェクト (変数) を並べ替えることができます。

[] int、[] float64、および [] string の場合、特別に指定された関数を使用するだけでなく、変更された型 IntSclice、Float64Slice、および StringSlice を使用して、対応する Sort() メソッドを直接呼び出すこともできます。これら 3 つの型は sort.Interface インターフェイスも実装しているため、sort.Reverse を使用してこれら 3 つの型の Interface.Less メソッドを変換し、逆順の並べ替えを実現できます。これが最後の並べ替えの使用法です。

以下では、sort.Reverse 関数の代わりにカスタム (ユーザー定義) Reverse 構造を使用して、逆ソートを実装します。

package main
 
import (
    "fmt"
    "sort"
)
 
// 自定义的 Reverse 类型
type Reverse struct {
    sort.Interface    // 这样, Reverse 可以接纳任何实现了 sort.Interface (包括 Len, Less, Swap 三个方法) 的对象
}
 
// Reverse 只是将其中的 Inferface.Less 的顺序对调了一下
func (r Reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}
 
func main() {
    ints := []int{5, 2, 6, 3, 1, 4}     // 未排序
 
    sort.Ints(ints)                                     // 特殊排序函数, 升序
    fmt.Println("after sort by Ints:\t", ints)  // [1 2 3 4 5 6]
 
    doubles := []float64{2.3, 3.2, 6.7, 10.9, 5.4, 1.8}
 
    sort.Float64s(doubles)                                      // float64 排序版本 1
    fmt.Println("after sort by Float64s:\t", doubles)   // [1.8 2.3 3.2 5.4 6.7 10.9]
 
    strings := []string{"hello", "good", "students", "morning", "people", "world"}
    sort.Strings(strings)
    fmt.Println("after sort by Strings:\t", strings)    // [good hello mornig people students world]
 
    ipos := sort.SearchInts(ints, -1)    // int 搜索
    fmt.Printf("pos of 5 is %d th\n", ipos)     // 并不总是正确呀 ! (搜索不是重点)
 
    dpos := sort.SearchFloat64s(doubles, 20.1)    // float64 搜索
    fmt.Printf("pos of 5.0 is %d th\n", dpos)   // 并不总是正确呀 !
 
    fmt.Printf("doubles is asc ? %v\n", sort.Float64sAreSorted(doubles))
 
    doubles = []float64{3.5, 4.2, 8.9, 100.98, 20.14, 79.32}
    // sort.Sort(sort.Float64Slice(doubles))    // float64 排序方法 2
    // fmt.Println("after sort by Sort:\t", doubles)    // [3.5 4.2 8.9 20.14 79.32 100.98]
    (sort.Float64Slice(doubles)).Sort()         // float64 排序方法 3
    fmt.Println("after sort by Sort:\t", doubles)       // [3.5 4.2 8.9 20.14 79.32 100.98]
 
    sort.Sort(Reverse{sort.Float64Slice(doubles)})    // float64 逆序排序
    fmt.Println("after sort by Reversed Sort:\t", doubles)      // [100.98 79.32 20.14 8.9 4.2 3.5]
}

sort.Ints / sort.Float64s / sort.Strings は、整数/浮動小数点/文字列型のスライス、フラグメント、または厳密には配列ではないものをソートするために使用されます。次に、それが正しいかどうかをテストする機能があります。対応する検索機能もありますが、検索機能では位置が存在する場合のみ位置を特定でき、存在しない場合は位置が間違っていることがわかります。

一般的な配列のソートに関して、プログラムは 3 つの方法があることを示しています。現在提供されている 3 つの型、int、float64、string は対称的です。つまり、あなたが持っているものは、私も対応するものを持っています。

反転ソートまたは逆ソートについては、flip 構造体を使用して Less 関数を書き直すだけです。上記の逆は一般的な構造です。

上ではこれまで述べてきましたが、基本的な型のみがソートされています。ここで、構造体の型のソートについて説明します。実際には、これはさらに使用されます。

構造型の並べ替え

構造型の並べ替えは、slice が実装されている限り、sort.Sort(slice) を使用して実現されます。 sort.Interface の 3 つのメソッドで十分です。そうは言っても、並べ替える方法はいくつかあります。 1 つ目は、[] int のソートをシミュレートして対応する IntSlice 型を構築し、次に IntSlice 型の Interface の 3 つのメソッドを実装することです。

構造ソート方法 1

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
// 按照 Person.Age 从大到小排序
type PersonSlice [] Person
 
func (a PersonSlice) Len() int {    // 重写 Len() 方法
    return len(a)
}
func (a PersonSlice) Swap(i, j int){     // 重写 Swap() 方法
    a[i], a[j] = a[j], a[i]
}
func (a PersonSlice) Less(i, j int) bool {    // 重写 Less() 方法, 从大到小排序
    return a[j].Age < a[i].Age
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonSlice(people))    // 按照 Age 的逆序排序
    fmt.Println(people)
 
    sort.Sort(sort.Reverse(PersonSlice(people)))    // 按照 Age 的升序排序
    fmt.Println(people)
 
}

これは完全にシミュレーション方法なので、IntSlice を理解していれば自然と理解できますし、逆にこれも理解できます。そうすれば、IntSlice は理解します。

構造分類法2

方法 1 的缺点是 : 根据 Age 排序需要重新定义 PersonSlice 方法,绑定 Len 、 Less 和 Swap 方法, 如果需要根据 Name 排序, 又需要重新写三个函数; 如果结构体有 4 个字段,有四种类型的排序,那么就要写 3 × 4 = 12 个方法, 即使有一些完全是多余的, 仔细思量一下,根据不同的标准 Age 或是 Name, 真正不同的体现在 Less 方法上,所以, me 们将 Less 抽象出来, 每种排序的 Less 让其变成动态的,比如下面一种方法。

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
type PersonWrapper struct {
    people [] Person
    by func(p, q * Person) bool
}
 
func (pw PersonWrapper) Len() int {    // 重写 Len() 方法
    return len(pw.people)
}
func (pw PersonWrapper) Swap(i, j int){     // 重写 Swap() 方法
    pw.people[i], pw.people[j] = pw.people[j], pw.people[i]
}
func (pw PersonWrapper) Less(i, j int) bool {    // 重写 Less() 方法
    return pw.by(&pw.people[i], &pw.people[j])
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return q.Age < p.Age    // Age 递减排序
    }})
 
    fmt.Println(people)
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return p.Name < q.Name    // Name 递增排序
    }})
 
    fmt.Println(people)
 
}

方法 2 将 [] Person 和比较的准则 cmp 封装在了一起,形成了 PersonWrapper 函数,然后在其上绑定 Len 、 Less 和 Swap 方法。 实际上 sort.Sort(pw) 排序的是 pw 中的 people, 这就是前面说的, go 的排序未必就是针对的一个数组或是 slice, 而可以是一个对象中的数组或是 slice 。

结构体排序方法 3

me 赶脚方法 2 已经很不错了, 唯一一个缺点是,在 main 中使用的时候暴露了 sort.Sort 的使用,还有就是 PersonWrapper 的构造。 为了让 main 中使用起来更为方便, me 们可以再简单的封装一下, 构造一个 SortPerson 方法, 如下:

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
type PersonWrapper struct {
    people [] Person
    by func(p, q * Person) bool
}
 
type SortBy func(p, q *Person) bool
 
func (pw PersonWrapper) Len() int {    // 重写 Len() 方法
    return len(pw.people)
}
func (pw PersonWrapper) Swap(i, j int){     // 重写 Swap() 方法
    pw.people[i], pw.people[j] = pw.people[j], pw.people[i]
}
func (pw PersonWrapper) Less(i, j int) bool {    // 重写 Less() 方法
    return pw.by(&pw.people[i], &pw.people[j])
}
 
 
func SortPerson(people [] Person, by SortBy){    // SortPerson 方法
    sort.Sort(PersonWrapper{people, by})
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return q.Age < p.Age    // Age 递减排序
    }})
 
    fmt.Println(people)
 
    SortPerson(people, func (p, q *Person) bool {
        return p.Name < q.Name    // Name 递增排序
    })
 
    fmt.Println(people)
 
}

在方法 2 的基础上构造了 SortPerson 函数,使用的时候传过去一个 [] Person 和一个 cmp 函数。

结构体排序方法 4

下面是另外一个实现思路, 可以说是方法 1、 2 的变体。

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name        string
    Weight      int
}
 
type PersonSlice []Person
 
func (s PersonSlice) Len() int  { return len(s) }
func (s PersonSlice) Swap(i, j int)     { s[i], s[j] = s[j], s[i] }
 
type ByName struct{ PersonSlice }    // 将 PersonSlice 包装起来到 ByName 中
 
func (s ByName) Less(i, j int) bool     { return s.PersonSlice[i].Name < s.PersonSlice[j].Name }    // 将 Less 绑定到 ByName 上
 
 
type ByWeight struct{ PersonSlice }    // 将 PersonSlice 包装起来到 ByWeight 中
func (s ByWeight) Less(i, j int) bool   { return s.PersonSlice[i].Weight < s.PersonSlice[j].Weight }    // 将 Less 绑定到 ByWeight 上
 
func main() {
    s := []Person{
        {"apple", 12},
        {"pear", 20},
        {"banana", 50},
        {"orange", 87},
        {"hello", 34},
        {"world", 43},
    }
 
    sort.Sort(ByWeight{s})
    fmt.Println("People by weight:")
    printPeople(s)
 
    sort.Sort(ByName{s})
    fmt.Println("\nPeople by name:")
    printPeople(s)
 
}
 
func printPeople(s []Person) {
    for _, o := range s {
        fmt.Printf("%-8s (%v)\n", o.Name, o.Weight)
    }
}

更多go语言知识请关注PHP中文网go语言教程栏目。

以上がGo言語でのソート説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事は博客园で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
GOプログラミング言語を備えたスケーラブルなシステムを構築しますGOプログラミング言語を備えたスケーラブルなシステムを構築しますApr 25, 2025 am 12:19 AM

goisidealforbuildingscalablessystemsduetoitssimplicity、効率性、およびビルド・インコンカレンシsupport.1)

GOでINIT機能を効果的に使用するためのベストプラクティスGOでINIT機能を効果的に使用するためのベストプラクティスApr 25, 2025 am 12:18 AM

intionSingOrunautomaticallyは()andareuseforstingupenments andinitializingvariables.usemforsimpletasks、回避効果を回避し、測定可能性を測定することを検討します。

GOパッケージのINIT機能の実行順序GOパッケージのINIT機能の実行順序Apr 25, 2025 am 12:14 AM

goinitializeSpackages intheordertheyareimport extionsitions withinitionsiteintheirdefinition ordord、およびfilenamesdetermineTheOordCrossMultiplefiles.thisprocesccanbeandeanded by -dependenciessedieSiesは、このマイレアドカンフレシニティン化の対象となります

Goでカスタムインターフェイスを定義および使用しますGoでカスタムインターフェイスを定義および使用しますApr 25, 2025 am 12:09 AM

custominterfacesingoarecrucialforwritingfficable、maintable、a​​ndtatablecode.theyeNabledeveloveerStofofofovioroverimplementation、拡張、methodsodsignaturesthattypespessmustimment、interfaceforoderueusavelya

GOのモッキングとテストのためにインターフェイスを使用しますGOのモッキングとテストのためにインターフェイスを使用しますApr 25, 2025 am 12:07 AM

シミュレーションとテストにインターフェイスを使用する理由は、インターフェイスにより、実装を指定せずに契約の定義を可能にし、テストをより孤立し、メンテナンスしやすくするためです。 1)インターフェイスの暗黙的な実装により、モックオブジェクトを簡単に作成できます。これにより、テストの実際の実装を置き換えることができます。 2)インターフェイスを使用すると、ユニットテストでのサービスの実際の実装を簡単に置き換えることができ、テストの複雑さと時間を短縮できます。 3)インターフェイスによって提供される柔軟性により、さまざまなテストケースのシミュレートされた動作の変更が可能になります。 4)インターフェイスは、テスト可能なコードを最初から設計し、コードのモジュール性と保守性を向上させるのに役立ちます。

GOのパッケージ初期化にinitを使用しますGOのパッケージ初期化にinitを使用しますApr 24, 2025 pm 06:25 PM

Goでは、init関数はパッケージの初期化に使用されます。 1)init関数は、パッケージの初期化時に自動的に呼び出され、グローバル変数の初期化、接続の設定、構成ファイルの読み込みに適しています。 2)ファイルの順序で実行できる複数のinit関数がある場合があります。 3)それを使用する場合、実行順序、テストの難易度、パフォーマンスへの影響を考慮する必要があります。 4)副作用を減らし、依存関係の注入を使用し、初期化を遅延させることをお勧めします。

GoのSelectステートメント:マルチプレックスコンカレント操作GoのSelectステートメント:マルチプレックスコンカレント操作Apr 24, 2025 pm 05:21 PM

go'sselectStatementStreamLinesConcurrentProgrambyMultipLexIngoperations.1)Itallow swaitingonMultipleChanneloperations、実行、exectingThefirstreadyone.2)

Go:Context and Waitgroupsの高度な並行性テクニックGo:Context and Waitgroupsの高度な並行性テクニックApr 24, 2025 pm 05:09 PM

コンテキストアンドウェイトグループは、フォーマネングに焦点を合わせており、contextAllowsingSignalingCancellationAndDeadlinesAcrossapiboundariesを採用し、GoroutinesscanSclacefly.2)WaitGroupssynchronizeGoroutines、Allcompletebebroproproproproproproprotinesを保証します

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター