<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Golang 高效處理集合 (Collection) 的庫

          共 28828字,需瀏覽 58分鐘

           ·

          2024-05-11 21:02

          處理集合是構(gòu)建任何應(yīng)用程序的重要部分。通常,需要以下幾類操作:

          • 轉(zhuǎn)換:將某個函數(shù)應(yīng)用于集合中的每個元素,以創(chuàng)建一個新類型的新集合;
          • 過濾:選擇滿足特定條件的集合中的元素;
          • 聚合:從集合中計算出單個結(jié)果,通常用于匯總;
          • 排序/排序:根據(jù)某些標(biāo)準(zhǔn)重新排列集合的元素;
          • 訪問:根據(jù)其屬性或位置檢索元素的操作;
          • 實用程序:與集合一起工作的通用操作,但不一定完全適合上述分類。

          盡管 Go 具有許多優(yōu)點,但對于高級集合操作的內(nèi)置支持相對有限,因此如果需要,需要使用第三方包。在本文中,我將探討幾個流行的 Go 庫,這些庫可以增強(qiáng)語言的能力,以有效地處理集合,涵蓋它們的功能和功能。這篇評論將幫助開發(fā)者選擇合適的工具,以簡化 Go 項目中的數(shù)據(jù)處理任務(wù)。

          Introduction

          讓我們從上面的每個集合操作類中回顧一些流行的方法。

          轉(zhuǎn)換

          Map — 對集合中的每個元素應(yīng)用一個函數(shù),并返回結(jié)果集合;FlatMap — 將每個元素處理為一個元素列表,然后將這些列表展平為一個列表。

          過濾

          Filter — 刪除不匹配謂詞函數(shù)的元素;Distinct — 從集合中刪除重復(fù)的元素;TakeWhile — 返回滿足給定條件的元素,直到遇到不滿足條件的元素為止;DropWhile — 刪除滿足給定條件的元素,然后返回剩余的元素。

          聚合

          Reduce — 使用給定的函數(shù)組合集合的所有元素,并返回組合結(jié)果;Count — 返回滿足特定條件的元素數(shù)量;Sum — 計算集合中每個元素的數(shù)字屬性之和;Max/Min — 確定元素屬性中的最大值或最小值;Average — 計算集合中元素的數(shù)字屬性的平均值。

          排序/排序

          Sort — 根據(jù)比較器規(guī)則對集合的元素進(jìn)行排序;Reverse — 顛倒集合中元素的順序。

          訪問

          Find — 返回匹配給定謂詞的第一個元素;AtIndex — 檢索特定索引處的元素。

          實用程序

          GroupBy — 根據(jù)鍵生成器函數(shù)將元素分類為組;Partition — 根據(jù)謂詞將集合分成兩個集合:一個用于滿足謂詞的元素,另一個用于不滿足謂詞的元素;Slice Operations — 修改集合視圖或劃分的操作,如切片或分塊。

          Go 內(nèi)置的能力

          在Go語言中,有幾種類型可用于處理數(shù)據(jù)集合:

          數(shù)組(Arrays) — 固定大小的元素集合。數(shù)組大小在聲明時定義,例如 var myArray [5]int;切片(Slices) — 動態(tài)大小的元素集合。切片建立在數(shù)組之上,但與數(shù)組不同的是,它們可以增長或縮小。聲明方式:mySlice := []int{1, 2, 3};映射(Maps) — 鍵-值對的集合。映射可以動態(tài)增長,且鍵的順序不受保證。例如 myMap := map[string]int{"first": 1, "second": 2} 創(chuàng)建了一個字符串鍵和整數(shù)值的映射;通道(Channels) — 類型化的通信原語,允許在goroutine之間共享數(shù)據(jù)。例如 myChan := make(chan int) 創(chuàng)建了一個傳輸整數(shù)的通道。

          Go標(biāo)準(zhǔn)庫提供了其他結(jié)構(gòu)和實用程序,可以作為集合或增強(qiáng)集合的功能,例如:

          堆(Heap) — container/heap包為任何sort.Interface提供了堆操作。堆是具有以下特性的樹:每個節(jié)點都是其子樹中值最小的節(jié)點;鏈表(List) — container/list包實現(xiàn)了雙向鏈表;環(huán)形鏈表(Ring) — container/ring包實現(xiàn)了環(huán)形鏈表的操作。

          此外,作為Go標(biāo)準(zhǔn)庫的一部分,還有用于處理切片和映射的包:

          slices — 該包定義了與任何類型的切片一起使用的各種有用的函數(shù);maps — 該包定義了與任何類型的映射一起使用的各種有用的函數(shù)。

          通過內(nèi)置功能,我可以對集合執(zhí)行一些操作:

          獲取數(shù)組/切片/映射的長度;通過索引/鍵訪問元素,對切片進(jìn)行“切片”;遍歷項目。

          package main

          import "fmt"

          func main() {
           s := []int{12345}
           m := map[int]string{1"one"2"two"3"three"}

           fmt.Printf("len(s)=%d\n"len(s))
           fmt.Printf("len(m)=%d\n"len(m))
           fmt.Printf("cap(s)=%d\n"cap(s))
           // fmt.Printf("cap(m)=%d\n", cap(m)) // error: invalid argument m (type map[int]string) for cap

           // panic: runtime error: index out of range [5] with length 5
           // fmt.Printf("s[5]=%d\n", s[5])

           // panic: runtime error: index out of range [5] with length 5
           // s[5] = 6

           s = append(s, 6)
           fmt.Printf("s=%v\n", s)
           fmt.Printf("len(s)=%d\n"len(s))
           fmt.Printf("cap(s)=%d\n"cap(s))

           m[4] = "four"
           fmt.Printf("m=%v\n", m)

           fmt.Printf("s[2:4]=%v\n", s[2:4])
           fmt.Printf("s[2:]=%v\n", s[2:])
           fmt.Printf("s[:2]=%v\n", s[:2])
           fmt.Printf("s[:]=%v\n", s[:])
          }

          上面的代碼會打?。?/p>

          len(s)=5
          len(m)=3
          cap(s)=5
          s=[1 2 3 4 5 6]
          len(s)=6
          cap(s)=10
          m=map[1:one 2:two 3:three 4:four]
          s[2:4]=[3 4]
          s[2:]=[3 4 5 6]
          s[:2]=[1 2]
          s[:]=[1 2 3 4 5 6]

          讓我們逐個看下 Go 內(nèi)置的 Package。

          Slices

          切片 slices包最近才出現(xiàn)在Go標(biāo)準(zhǔn)庫中,從Go 1.21版本開始。這是語言中的一個重大進(jìn)步,但我仍然更喜歡使用外部庫來處理集合。讓我們來看看這個庫如何支持所有的集合操作類別。

          Aggregation

          slices 能夠快速在切片中找到最小/最大值:

          package main

          import (
           "fmt"
           "slices"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           s := []int{12345}

           fmt.Printf("Min: %d\n", slices.Min(s))
           fmt.Printf("Max: %d\n", slices.Max(s))

           e := []Example{
            {"A"1},
            {"B"2},
            {"C"3},
            {"D"4},
           }

           fmt.Printf("Min: %v\n", slices.MinFunc(
            e,
            func(i, j Example) int {
             return i.Number - j.Number
            }),
           )

           fmt.Printf("Max: %v\n", slices.MaxFunc(
            e,
            func(i, j Example) int {
             return i.Number - j.Number
            }),
           )
          }

          上面的代碼打?。?/p>

          Min: 1
          Max: 5
          Min: {A 1}
          Max: {D 4}

          Sorting/Ordering

          slices 能夠使用比較函數(shù)對切片進(jìn)行排序:

          package main

          import (
           "fmt"
           "slices"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           s := []int{42513}

           slices.Sort(s)
           fmt.Printf("Sorted: %v\n", s)

           slices.Reverse(s)
           fmt.Printf("Reversed: %v\n", s)

           e := []Example{
            {"C"3},
            {"A"1},
            {"D"4},
            {"B"2},
           }

           slices.SortFunc(e, func(a, b Example) int {
            return a.Number - b.Number
           })

           fmt.Printf("Sorted: %v\n", e)

           slices.Reverse(e)
           fmt.Printf("Reversed: %v\n", e)
          }
          Sorted: [1 2 3 4 5]
          Reversed: [5 4 3 2 1]
          Sorted: [{A 1} {B 2} {C 3} {D 4}]
          Reversed: [{D 4} {C 3} {B 2} {A 1}]

          不過這個方法有個缺點,就是排序是原地進(jìn)行的,修改了原始切片。如果該方法返回一個新的排序后的切片,從而保留原始數(shù)組會更好一點。

          訪問元素

          slices暴露了一些方法,允許用戶在切片中查找元素的位置:

          package main

          import (
           "fmt"
           "slices"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           s := []int{42513}

           i := slices.Index(s, 3)
           fmt.Printf("Index of 3: %d\n", i)

           e := []Example{
            {"C"3},
            {"A"1},
            {"D"4},
            {"B"2},
           }

           i = slices.IndexFunc(e, func(a Example) bool {
            return a.Number == 3
           })

           fmt.Printf("Index of 3: %d\n", i)
          }
          Index of 3: 4
          Index of 3: 0

          如果你正在處理已排序的切片,你可以使用 BinarySearch 或 BinarySearchFunc 在排序的切片中搜索目標(biāo),并返回目標(biāo)被找到的位置或目標(biāo)將出現(xiàn)在排序順序中的位置;它還返回一個布爾值,指示目標(biāo)是否在切片中被找到。切片必須按遞增順序排序。

          package main

          import (
           "fmt"
           "slices"
          )

          func main() {
           s := []int{42513}

           slices.Sort(s)

           i, found := slices.BinarySearch(s, 3)
           fmt.Printf("Position of 3: %d. Found: %t\n", i, found)

           i, found = slices.BinarySearch(s, 6)
           fmt.Printf("Position of 6: %d. Found: %t\n", i, found)
          }
          Position of 3: 2. Found: true
          Position of 6: 5. Found: false

          實用函數(shù)

          slices提供了許多實用函數(shù):

          package main

          import (
           "fmt"
           "slices"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           e1 := []Example{
            {"C", 3},
            {"A", 1},
            {"D", 4},
            {"B", 2},
           }

           e2 := []Example{
            {"A", 1},
            {"B", 2},
            {"C", 3},
            {"D", 4},
           }

           fmt.Printf("Compare: %v\n", slices.CompareFunc(e1, e2, func(a, b Example) int {
            return a.Number - b.Number
           }))

           fmt.Printf("Contains: %v\n", slices.ContainsFunc(e1, func(a Example) bool {
            return a.Number == 2
           }))

           fmt.Printf("Delete: %v\n", slices.Delete(e1, 2, 3))
           fmt.Printf("Equal: %v\n", slices.Equal(e1, e2))

           fmt.Printf("Is Sorted: %v\n", slices.IsSortedFunc(e1, func(a, b Example) int {
            return a.Number - b.Number
           }))
          }
          Compare: 2
          Contains: true
          Delete: [{C 3} {A 1} {B 2}]
          Equal: false
          Is Sorted: false

          slices 包的官方文檔地址[1]

          Map

          類似于slices,maps也是從Go 1.21開始出現(xiàn)在Go標(biāo)準(zhǔn)庫中的。它定義了各種方法來操作 maps。

          package main

          import (
           "fmt"
           "maps"
          )

          func main() {
           m := map[int]string{1"one"2"two"3"three"}
           c := maps.Clone(m)

           c[4] = "four"

           fmt.Printf("Original: %v\n", m)
           fmt.Printf("Clone: %v\n", c)

           maps.DeleteFunc(c, func(k int, v string) bool { return k%2 == 0 })
           fmt.Printf("DeleteFunc: %v\n", c)

           fmt.Printf("Equal: %v\n", maps.Equal(m, c))
           fmt.Printf("EqualFunc: %v\n", maps.EqualFunc(m, c, func(v1, v2 string) bool { return v1 == v2 }))
          }

          Original: map[1:one 2:two 3:three]
          Clone: map[1:one 2:two 3:three 4:four]
          DeleteFunc: map[1:one 3:three]
          Equal: false
          EqualFunc: false

          maps 包的官方文檔地址[2]

          github.com/elliotchance/pie

          這是我個人最喜歡的用來操作切片和映射的包。它提供了一種獨(dú)特的語法,能夠無縫地鏈接操作,提高了代碼的可讀性和效率。

          使用庫方法有四種方式:

          1. 純調(diào)用 — 只需調(diào)用庫方法并提供所需的參數(shù);
          2. pie.Of — 鏈接多個操作,支持任何元素類型;
          3. pie.OfOrdered — 鏈接多個操作,支持?jǐn)?shù)字和字符串類型;
          4. pie.OfNumeric — 鏈接多個操作,僅支持?jǐn)?shù)字類型。
          package main

          import (
           "fmt"
           "strings"

           "github.com/elliotchance/pie/v2"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           e := []Example{
            {"C"3},
            {"A"1},
            {"D"4},
            {"B"2},
           }

           fmt.Printf(
            "Map 1: %v\n",
            pie.Sort(
             pie.Map(
              e,
              func(e Example) string {
               return e.Name
              },
             ),
            ),
           )

           fmt.Printf(
            "Map 2: %v\n",
            pie.Of(e).
             Map(func(e Example) Example {
              return Example{
               Name:   e.Name,
               Number: e.Number * 2,
              }
             }).
             SortUsing(func(a, b Example) bool {
              return a.Number < b.Number
             }),
           )

           fmt.Printf(
            "Map 3: %v\n",
            pie.OfOrdered([]string{"A""C""B""A"}).
             Map(func(e string) string {
              return strings.ToLower(e)
             }).
             Sort(),
           )

           fmt.Printf(
            "Map 4: %v\n",
            pie.OfNumeric([]int{4132}).
             Map(func(e int) int {
              return e * 2
             }).
             Sort(),
           )
          }
          Map 1: [A B C D]
          Map 2: {[{A 2} {B 4} {C 6} {D 8}]}
          Map 3: {[a a b c]}
          Map 4: {[2 4 6 8]}

          由于諸如 Map 等函數(shù)應(yīng)該返回相同類型的集合,因此這個庫的鏈?zhǔn)讲僮飨喈?dāng)受限。因此,我認(rèn)為純方法調(diào)用是使用這個庫的最佳方式。

          該庫提供了 Map 方法,允許將每個元素從一種類型轉(zhuǎn)換為另一種類型。

          package main

          import (
           "fmt"

           "github.com/elliotchance/pie/v2"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           e := []Example{
            {"C"3},
            {"A"1},
            {"D"4},
            {"B"2},
           }

           fmt.Printf(
            "Map: %v\n",
            pie.Map(
             e,
             func(e Example) string {
              return e.Name
             },
            ),
           )
          }

          還提供了 Flat 方法,它將二維切片轉(zhuǎn)換為一維切片。

          package main

          import (
           "fmt"

           "github.com/elliotchance/pie/v2"
          )

          type Person struct {
           Name string
           Tags []string
          }

          func main() {
           p := []Person{
            {"Alice", []string{"a""b""c"}},
            {"Bob", []string{"b""c""d"}},
            {"Charlie", []string{"c""d""e"}},
           }

           fmt.Printf(
            "Unique Tags: %v\n",
            pie.Unique(
             pie.Flat(
              pie.Map(
               p,
               func(e Person) []string {
                return e.Tags
               },
              ),
             ),
            ),
           )
          }
          Unique Tags: [b c d e a]

          使用 Keys 或 Values 方法可以僅獲取 Map 的鍵或值。

          package main

          import (
           "fmt"

           "github.com/elliotchance/pie/v2"
          )

          func main() {
           m := map[int]string{
            1"one",
            2"two",
            3"three",
           }

           fmt.Printf("Keys: %v\n", pie.Keys(m))
           fmt.Printf("Values: %v\n", pie.Values(m))
          }

          Output:

          Keys: [3 1 2]
          Values: [one two three]

          Filter

          該庫提供了幾種過濾原始集合的方法:Bottom、DropTop、DropWhile、Filter、FilterNot、Unique 等。

          Bottom 3: [4 4 4]
          Drop top 3: [3 3 3 4 4 4 4]
          Drop while 3: [3 3 3 4 4 4 4]
          Filter even: [2 2 4 4 4 4]
          Filter not even: [1 3 3 3]
          Unique values: [1 2 3 4]

          Aggregation

          有一個通用的聚合方法 Reduce。讓我們來計算標(biāo)準(zhǔn)差:

          package main

          import (
           "fmt"
           "math"

           "github.com/elliotchance/pie/v2"
          )

          func main() {
           v := []float64{1.12.23.34.45.5}

           avg := pie.Average(v)
           count := len(v)

           sum2 := pie.Reduce(
            v,
            func(acc, value float64) float64 {
             return acc + (value-avg)*(value-avg)
            },
           ) - v[0] + (v[0]-avg)*(v[0]-avg)

           d := math.Sqrt(sum2 / float64(count))

           fmt.Printf("Standard deviation: %f\n", d)
          }

          Output:

          Standard deviation: 1.555635

          Reduce 方法首先將第一個切片元素作為累積值,將第二個元素作為值參數(shù)調(diào)用 reducer。這就是為什么公式看起來很奇怪。

          從下面的示例中,可以找到另一個內(nèi)置的聚合方法 Average。此外,還可以找到 Min、Max、Product 等方法。

          package main

          import (
           "fmt"

           "github.com/elliotchance/pie/v2"
          )

          func main() {
           v := []float64{1.12.23.34.45.5}

           fmt.Printf("Average: %f\n", pie.Average(v))
           fmt.Printf("Stddev: %f\n", pie.Stddev(v))
           fmt.Printf("Max: %f\n", pie.Max(v))
           fmt.Printf("Min: %f\n", pie.Min(v))
           fmt.Printf("Sum: %f\n", pie.Sum(v))
           fmt.Printf("Product: %f\n", pie.Product(v))

           fmt.Printf("All >0: %t\n", pie.Of(v).All(func(value float64) bool { return value > 0 }))
           fmt.Printf("Any >5: %t\n", pie.Of(v).Any(func(value float64) bool { return value > 5 }))

           fmt.Printf("First: %f\n", pie.First(v))
           fmt.Printf("Last: %f\n", pie.Last(v))

           fmt.Printf("Are Unique: %t\n", pie.AreUnique(v))
           fmt.Printf("Are Sorted: %t\n", pie.AreSorted(v))
           fmt.Printf("Contains 3.3: %t\n", pie.Contains(v, 3.3))
          }
          Average: 3.300000
          Stddev: 1.555635
          Max: 5.500000
          Min: 1.100000
          Sum: 16.500000
          Product: 193.261200
          All >0: true
          Any >5: true
          First: 1.100000
          Last: 5.500000
          Are Unique: true
          Are Sorted: true
          Contains 3.3: true

          Sorting/Ordering

          有三種不同的方法可以使用 pie 對切片進(jìn)行排序:

          Sort — 類似于 sort.Slice。但與 sort.Slice 不同的是,返回的切片將被重新分配,以不修改輸入切片;SortStableUsing — 類似于 sort.SliceStable。但與 sort.SliceStable 不同的是,返回的切片將被重新分配,以不修改輸入切片;SortUsing — 類似于 sort.Slice。但與 sort.Slice 不同的是,返回的切片將被重新分配,以不修改輸入切片。

          package main

          import (
           "fmt"

           "github.com/elliotchance/pie/v2"
          )

          func main() {
           v := []int{3, 5, 1, 4, 2}

           less := func(a, b int) bool {
            return a < b
           }

           fmt.Printf("Sort: %v\n", pie.Sort(v))
           fmt.Printf("SortStableUsing: %v\n", pie.SortStableUsing(v, less))
           fmt.Printf("SortUsing: %v\n", pie.SortUsing(v, less))
           fmt.Printf("Original: %v\n", v)
          }

          Output:

          Sort: [1 2 3 4 5]
          SortStableUsing: [1 2 3 4 5]
          SortUsing: [1 2 3 4 5]
          Original: [3 5 1 4 2]

          Access

          pie 提供了 FindFirstUsing 方法,用于獲取切片中第一個與謂詞匹配的元素的索引。

          package main

          import (
           "fmt"

           "github.com/elliotchance/pie/v2"
          )

          type Person struct {
           Name string
           Age  int
          }

          func main() {
           p := []Person{
            {"Alice"25},
            {"Bob"30},
            {"Charlie"35},
           }

           fmt.Printf(
            "FindFirstUsing: %v\n",
            pie.FindFirstUsing(
             p,
             func(p Person) bool {
              return p.Age >= 30
             },
            ),
           )

          }
          FindFirstUsing: 2

          pie 包含許多用于處理切片的實用方法。舉幾個例子:

          package main

          import (
           "fmt"
           "math/rand"
           "time"

           "github.com/elliotchance/pie/v2"
          )

          type Person struct {
           Name string
           Age  int
          }

          func main() {
           p := []Person{
            {"Alice"25},
            {"Bob"30},
            {"Charlie"35},
            {"David"25},
            {"Eve"40},
            {"Frank"35},
           }

           fmt.Printf("Chunk: %v\n", pie.Chunk(p, 2))
           fmt.Printf("GroupBy: %v\n", pie.GroupBy(p, func(p Person) int { return p.Age }))
           fmt.Printf("Shuffle: %v\n", pie.Shuffle(p, rand.New(rand.NewSource(time.Now().UnixNano()))))
          }

          Output:

          Chunk: [[{Alice 25} {Bob 30}] [{Charlie 35} {David 25}] [{Eve 40} {Frank 35}]]
          GroupBy: map[25:[{Alice 25} {David 25}] 30:[{Bob 30}] 35:[{Charlie 35} {Frank 35}] 40:[{Eve 40}]]
          Shuffle: [{Frank 35} {Bob 30} {David 25} {Eve 40} {Alice 25} {Charlie 35}]

          下面是 pie 包的地址[3]

          elliotchance/pie/v2 庫提供了一套非常完整的的處理集合的能力,極大地簡化了在 Go 中處理切片的工作。其強(qiáng)大的方法用于操作和查詢切片數(shù)據(jù),為開發(fā)人員提供了一個強(qiáng)大的工具,增強(qiáng)了代碼的可讀性和效率。我強(qiáng)烈建議任何 Go 開發(fā)人員在下一個項目中嘗試使用這個庫。

          github.com/samber/lo

          另一個在 Go 中操作集合的流行庫。在某些方面,它可能類似于流行的 JavaScript 庫 Lodash。它在內(nèi)部使用泛型,而不是反射。

          Transform

          該庫支持默認(rèn)的 MapFlatMap 方法用于切片:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          type Example struct {
           Name   string
           Number int
          }

          func main() {
           e := []Example{
            {"C"3},
            {"A"1},
            {"D"4},
            {"B"2},
           }

           fmt.Printf(
            "Map: %v\n",
            lo.Map(
             e,
             func(e Example, index int) string {
              return e.Name
             },
            ),
           )
          }

          Map: [C A D B]

          下面的代碼演示如何操作 FlatMap:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          type Person struct {
           Name string
           Tags []string
          }

          func main() {
           p := []Person{
            {"Alice", []string{"a""b""c"}},
            {"Bob", []string{"b""c""d"}},
            {"Charlie", []string{"c""d""e"}},
           }

           fmt.Printf(
            "Unique Tags: %v\n",
            lo.Uniq(
             lo.FlatMap(
              p,
              func(e Person, index int) []string {
               return e.Tags
              },
             ),
            ),
           )
          }

          此外,還可以獲取映射鍵、值或?qū)⒂成鋵D(zhuǎn)換為某些切片等操作:

          package main

          import (
           "fmt"
           "strings"

           "github.com/samber/lo"
          )

          func main() {
           m := map[int]string{
            1"one",
            2"two",
            3"three",
           }

           fmt.Printf("Keys: %v\n", lo.Keys(m))
           fmt.Printf("Values: %v\n", lo.Values(m))
           fmt.Printf("MapKeys: %v\n", lo.MapKeys(m, func(value string, num int) int { return num * 2 }))
           fmt.Printf("MapValues: %v\n", lo.MapValues(m, func(value string, num int) string { return strings.ToUpper(value) }))
           fmt.Printf("MapToSlice: %v\n", lo.MapToSlice(m, func(num int, value string) string { return value + ":" + fmt.Sprint(num) }))
          }

          Outputs:

          Keys: [2 3 1]
          Values: [one two three]
          MapKeys: map[2:one 4:two 6:three]
          MapValues: map[1:ONE 2:TWO 3:THREE]
          MapToSlice: [three:3 one:1 two:2]

          Filter

          在 lo 庫中有許多 Drop 方法:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           v := []int{1, 2, 3, 4, 5}

           fmt.Printf("Drop: %v\n", lo.Drop(v, 2))
           fmt.Printf("DropRight: %v\n", lo.DropRight(v, 2))
           fmt.Printf("DropWhile: %v\n", lo.DropWhile(v, func(i int) bool { return i < 3 }))
           fmt.Printf("DropRightWhile: %v\n", lo.DropRightWhile(v, func(i int) bool { return i > 3 }))
          }

          Outputs:

          Drop: [3 4 5]
          DropRight: [1 2 3]
          DropWhile: [3 4 5]
          DropRightWhile: [1 2 3]

          此外,還可以通過 predicate 過濾切片和映射:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           v := []int{12345}
           m := map[string]int{"a"1"b"2"c"3}

           fmt.Printf("Filter: %v\n", lo.Filter(v, func(i int, index int) bool { return i > 2 }))
           fmt.Printf("PickBy: %v\n", lo.PickBy(m, func(key string, value int) bool { return value > 2 }))
          }

          Outputs:

          Filter: [3 4 5]
          PickBy: map[c:3]

          Aggregation

          lo package 提供了 reduce 的方法:

          package main

          import (
           "fmt"
           "math"

           "github.com/samber/lo"
          )

          func main() {
           v := []float64{1.12.23.34.45.5}

           count := len(v)

           avg := lo.Reduce(v, func(acc, val float64, index int) float64 {
            return acc + val
           }, 0.0) / float64(count)

           sum2 := lo.Reduce(v, func(acc, val float64, index int) float64 {
            return acc + (val-avg)*(val-avg)
           }, 0.0)

           d := math.Sqrt(sum2 / float64(count))

           fmt.Printf("Standard deviation: %f\n", d)
          }

          Outputs:

          Standard deviation: 1.555635

          此外,它支持一些通用的聚合方法,如 Sum、Min、Max:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           v := []float64{1.12.23.34.45.5}

           fmt.Printf("Sum: %v\n", lo.Sum(v))
           fmt.Printf("Min: %v\n", lo.Min(v))
           fmt.Printf("Max: %v\n", lo.Max(v))
          }

          有一些有用的方法用于處理 channel:FanIn 和 FanOut

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           ch1 := make(chan int)
           ch2 := make(chan int)
           ch3 := make(chan int)

           ch := lo.FanIn(10, ch1, ch2, ch3)

           for i := 0; i < 10; i++ {
            if i%3 == 0 {
             ch1 <- i
            } else if i%3 == 1 {
             ch2 <- i
            } else {
             ch3 <- i
            }
           }

           close(ch1)
           close(ch2)
           close(ch3)

           for v := range ch {
            fmt.Println(v)
           }
          }

          還可以這樣處理 channel:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           ch := make(chan int)
           chs := lo.FanOut(310, ch)

           for i := 0; i < 3; i++ {
            ch <- i
           }

           close(ch)

           for _, ch := range chs {
            for v := range ch {
             fmt.Println(v)
            }
           }
          }

          Sorting/Ordering

          lo 還提供 Reverse 方法:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           v := []int{12345}

           fmt.Printf("Reverse: %v\n", lo.Reverse(v))
          }

          Access

          lo 庫提供了 find 方法來訪問元素:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          type Person struct {
           Name string
           Age  int
          }

          func main() {
           p := []Person{
            {"Alice"25},
            {"Bob"30},
            {"Charlie"35},
            {"David"25},
            {"Edward"40},
           }

           item, found := lo.Find(p, func(p Person) bool {
            return p.Name == "Charlie"
           })

           fmt.Printf("Item: %+v, Found: %v\n", item, found)

           fmt.Printf("FindDuplicatesBy: %v\n", lo.FindDuplicatesBy(p, func(p Person) int {
            return p.Age
           }))

           item, index, found := lo.FindIndexOf(p, func(p Person) bool {
            return p.Name == "Charlie"
           })

           fmt.Printf("Item: %+v, Index: %v, Found: %v\n", item, index, found)
          }

          Outputs:

          Item: {Name:Charlie Age:35}, Found: true
          FindDuplicatesBy: [{Alice 25}]
          Item: {Name:Charlie Age:35}, Index: 2, Found: true

          Find 方法同樣支持 map:

          package main

          import (
           "fmt"

           "github.com/samber/lo"
          )

          func main() {
           p := map[string]int{
            "Alice":   34,
            "Bob":     24,
            "Charlie"34,
            "David":   29,
            "Eve":     34,
           }

           key, found := lo.FindKey(p, 34)
           fmt.Printf("Key: %v, Found: %v\n", key, found)
          }

          lo 的文檔地址[4]

          總結(jié)

          這里只展示了 github.com/samber/lo 庫約 10% 的方法。這個庫提供了許多簡化函數(shù)處理的實用工具。對于 Go 開發(fā)人員來說,這個庫是一個非常全面的工具包。

          本文提供了一些在 Go 中處理集合時推薦的庫,希望對大家的開發(fā)工作有幫助。

          參考資料
          [1]

          slices: https://pkg.go.dev/slices?source=post_page-----8387cecdb8a4--------------------------------

          [2]

          maps: https://pkg.go.dev/maps?source=post_page-----8387cecdb8a4--------------------------------

          [3]

          pie: https://github.com/elliotchance/pie?source=post_page-----8387cecdb8a4--------------------------------

          [4]

          lo: https://github.com/samber/lo?source=post_page-----8387cecdb8a4--------------------------------


          瀏覽 265
          1點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          1點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  AV无码网 | 亚洲欧美日韩中文字幕无码 | 日韩视频一区二区三区在线播放免费观看 | 欧美国产一级操逼 | 俺去也影院 |