最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go中獲取兩個(gè)切片交集的六種實(shí)現(xiàn)方式

 更新時(shí)間:2025年12月07日 11:49:20   作者:golang學(xué)習(xí)記  
在Go開發(fā)中,切片交集(Intersection) 是高頻需求:用戶標(biāo)簽匹配、權(quán)限校驗(yàn)、數(shù)據(jù)去重同步,本文系統(tǒng)梳理從基礎(chǔ)到高階的 6 種實(shí)現(xiàn)方式,含泛型、結(jié)構(gòu)體、去重、性能對(duì)比,助你寫出工業(yè)級(jí)健壯代碼,需要的朋友可以參考下

基礎(chǔ)方法回顧

1. 雙重循環(huán)法(O(n²),簡(jiǎn)單但低效)

func intersectLoop[T comparable](a, b []T) []T {
	var res []T
	for _, x := range a {
		for _, y := range b {
			if x == y {
				res = append(res, x)
				break // 防止重復(fù)添加同一元素(若 a 有重復(fù))
			}
		}
	}
	return res
}

? 優(yōu)點(diǎn):無額外內(nèi)存,邏輯直觀
? 缺點(diǎn):n=10? 時(shí)性能急劇下降

2. Map 查表法(O(n+m),推薦通用解)

func intersectMap[T comparable](a, b []T) []T {
	set := make(map[T]struct{}, len(a))
	for _, v := range a {
		set[v] = struct{}{}
	}

	var res []T
	for _, v := range b {
		if _, ok := set[v]; ok {
			res = append(res, v)
			delete(set, v) // ← 關(guān)鍵:防止 b 中重復(fù)導(dǎo)致結(jié)果重復(fù)
		}
	}
	return res
}

注意:

  • 默認(rèn)保留 b 中元素順序
  • delete 可實(shí)現(xiàn)結(jié)果去重(若只需首次匹配)
  • 若需保留所有重復(fù)(多集交集),則不要 delete

3. 排序雙指針法(O(n log n),內(nèi)存友好)

import "sort"

func intersectSorted[T comparable](a, b []T) []T {
	// 創(chuàng)建副本避免修改原 slice
	aa, bb := make([]T, len(a)), make([]T, len(b))
	copy(aa, a)
	copy(bb, b)

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

	var res []T
	i, j := 0, 0
	for i < len(aa) && j < len(bb) {
		switch {
		case aa[i] == bb[j]:
			res = append(res, aa[i])
			i++
			j++
		case aa[i] < bb[j]:
			i++
		default:
			j++
		}
	}
	return res
}

? 適合大內(nèi)存受限場(chǎng)景(如嵌入式)
? 破壞原順序,且 T 必須可排序

高級(jí)方法

4. 【泛型通用版】交集函數(shù)(Go 1.18+)

結(jié)合 map 法 + 泛型,寫出生產(chǎn)級(jí)工具函數(shù)

// Intersection returns the intersection of two slices.
// Result preserves the order of elements in `a`, and removes duplicates.
// T must be comparable.
func Intersection[T comparable](a, b []T) []T {
	if len(a) == 0 || len(b) == 0 {
		return nil
	}

	// Step 1: Build lookup set from b (smaller one for memory efficiency)
	if len(b) < len(a) {
		a, b = b, a // ensure `a` is the smaller slice
	}
	set := make(map[T]struct{}, len(a))
	for _, v := range a {
		set[v] = struct{}{}
	}

	// Step 2: Iterate b, collect matches while preserving order & dedup
	seen := make(map[T]struct{}) // track emitted items
	var res []T
	for _, v := range b {
		if _, inA := set[v]; inA {
			if _, emitted := seen[v]; !emitted {
				res = append(res, v)
				seen[v] = struct{}{}
			}
		}
	}
	return res
}

? 優(yōu)勢(shì):

  • 自動(dòng)選小切片建 map → 節(jié)省內(nèi)存
  • 保留 b 的出現(xiàn)順序
  • 天然去重(結(jié)果每個(gè)元素唯一)
  • 泛型支持 int, string, struct{}(只要 comparable

5. 【結(jié)構(gòu)體交集】自定義等價(jià)判斷

當(dāng)元素是結(jié)構(gòu)體,且僅部分字段需參與比較時(shí)(如 User{ID, Name} 只按 ID 比較):

type User struct {
	ID   int
	Name string
}

// Key returns a comparable key for equality comparison
func (u User) Key() int { return u.ID }

// IntersectionBy extracts intersection using a key function
func IntersectionBy[T any, K comparable](a, b []T, key func(T) K) []T {
	keySet := make(map[K]struct{})
	for _, v := range a {
		keySet[key(v)] = struct{}{}
	}

	var res []T
	seen := make(map[K]struct{})
	for _, v := range b {
		k := key(v)
		if _, ok := keySet[k]; ok {
			if _, dup := seen[k]; !dup {
				res = append(res, v)
				seen[k] = struct{}{}
			}
		}
	}
	return res
}

// Usage
usersA := []User{{1, "Alice"}, {2, "Bob"}, {3, "Carol"}}
usersB := []User{{2, "Bob2"}, {4, "David"}, {1, "Alice2"}}

common := IntersectionBy(usersA, usersB, User.Key)
// → [{1 "Alice"}, {2 "Bob"}] (按 ID 匹配,保留 usersB 中的完整結(jié)構(gòu))

適用場(chǎng)景:

  • 數(shù)據(jù)庫(kù)記錄對(duì)比(按 ID)
  • API 響應(yīng)去重(按唯一鍵)
  • 忽略時(shí)間戳/版本字段的結(jié)構(gòu)體同步

6. 【多集交集】保留重復(fù)次數(shù)的交集

若需數(shù)學(xué)意義上的多重集交集(如 A=[1,1,2], B=[1,2,2] → 交集為 [1,2],各取 min(count)):

func IntersectionMultiset[T comparable](a, b []T) []T {
	// Count frequency in a
	freqA := make(map[T]int)
	for _, v := range a {
		freqA[v]++
	}

	// For each in b, take min(count)
	var res []T
	for _, v := range b {
		if cnt, ok := freqA[v]; ok && cnt > 0 {
			res = append(res, v)
			freqA[v]-- // consume one occurrence
		}
	}
	return res
}

// Example:
a := []int{1, 1, 2, 3}
b := []int{1, 2, 2, 4}
fmt.Println(IntersectionMultiset(a, b)) // → [1, 2]

性能對(duì)比( 10k 元素 string slice)

goos: linux
goarch: amd64
pkg: example
cpu: Intel(R) Core(TM) i7-10700K
BenchmarkIntersectLoop-16      	     3	 452,123,840 ns/op
BenchmarkIntersectMap-16       	  1000	   1,021,344 ns/op
BenchmarkIntersectSorted-16    	  1000	   1,241,892 ns/op
BenchmarkIntersectionGeneric-16	  1000	   1,045,217 ns/op

結(jié)論:

  • Map 法/泛型通用版 最快(~1ms
  • 循環(huán)法慢 400+ 倍,僅適用于 n < 100
  • 排序法略慢于 map,但內(nèi)存穩(wěn)定(無 hash 表開銷)

實(shí)際建議:優(yōu)先用 Intersection[T comparable] 泛型函數(shù),兼顧性能、可讀性、去重、順序。

實(shí)戰(zhàn)建議

場(chǎng)景推薦方案
快速原型 / 小數(shù)據(jù)(<100)雙重循環(huán) + break
通用場(chǎng)景(string/int)泛型 Intersection[T]
結(jié)構(gòu)體按字段比較IntersectionBy + key 函數(shù)
需保留重復(fù)次數(shù)(多集)IntersectionMultiset
內(nèi)存極其受限排序雙指針法
需要穩(wěn)定順序 + 去重泛型版(內(nèi)置順序+去重)

以上就是Go中獲取兩個(gè)切片交集的六種實(shí)現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于Go獲取兩個(gè)切片交集的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go數(shù)據(jù)庫(kù)遷移的實(shí)現(xiàn)步驟

    Go數(shù)據(jù)庫(kù)遷移的實(shí)現(xiàn)步驟

    本文主要介紹了Go數(shù)據(jù)庫(kù)遷移的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Go語言Mock單元測(cè)試的實(shí)現(xiàn)示例

    Go語言Mock單元測(cè)試的實(shí)現(xiàn)示例

    Go語言Mock單元測(cè)試通過模擬外部依賴實(shí)現(xiàn)隔離測(cè)試,解決傳統(tǒng)測(cè)試中的環(huán)境依賴、結(jié)果不穩(wěn)定和效率問題,感興趣的可以了解一下
    2025-11-11
  • 關(guān)于Golang變量初始化/類型推斷/短聲明的問題

    關(guān)于Golang變量初始化/類型推斷/短聲明的問題

    這篇文章主要介紹了關(guān)于Golang變量初始化/類型推斷/短聲明的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • golang 如何實(shí)現(xiàn)HTTP代理和反向代理

    golang 如何實(shí)現(xiàn)HTTP代理和反向代理

    這篇文章主要介紹了golang 實(shí)現(xiàn)HTTP代理和反向代理的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go實(shí)現(xiàn)HTTP請(qǐng)求轉(zhuǎn)發(fā)的示例代碼

    Go實(shí)現(xiàn)HTTP請(qǐng)求轉(zhuǎn)發(fā)的示例代碼

    請(qǐng)求轉(zhuǎn)發(fā)是一項(xiàng)核心且常見的功能,本文主要介紹了Go實(shí)現(xiàn)HTTP請(qǐng)求轉(zhuǎn)發(fā)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Go語言雙向鏈表list.List的實(shí)現(xiàn)示例

    Go語言雙向鏈表list.List的實(shí)現(xiàn)示例

    Go語言中的list.List是包提供的雙向鏈表實(shí)現(xiàn),具有高效的插入和刪除操作能力,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09
  • golang 實(shí)現(xiàn)并發(fā)求和

    golang 實(shí)現(xiàn)并發(fā)求和

    這篇文章主要介紹了golang 并發(fā)求和的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • GoLang string類型深入分析

    GoLang string類型深入分析

    string 作為 go 語言中的基礎(chǔ)類型,其實(shí)有一些需要反復(fù)揣摩的,可能是我們使用的場(chǎng)景太簡(jiǎn)單,也可能是我們不需要那可憐的一點(diǎn)優(yōu)化來提高性能,對(duì)它也就沒那么上心了
    2023-01-01
  • Go語言操作redis用法實(shí)例

    Go語言操作redis用法實(shí)例

    這篇文章主要介紹了Go語言操作redis用法,實(shí)例分析了Go語言操作redis的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Go語言之結(jié)構(gòu)體與方法

    Go語言之結(jié)構(gòu)體與方法

    這篇文章主要介紹了Go語言之結(jié)構(gòu)體與方法,結(jié)構(gòu)體是由一系列具有相同類型或不同類型的數(shù)據(jù)構(gòu)成的數(shù)據(jù)集合。下面我們就一起來學(xué)習(xí)什么是Go語言之結(jié)構(gòu)體
    2021-10-10

最新評(píng)論

兰溪市| 凤冈县| 邳州市| 旌德县| 德化县| 左权县| 鄯善县| 黄骅市| 澎湖县| 清河县| 鹤山市| 同江市| 阿拉尔市| 镶黄旗| 大港区| 安宁市| 丰城市| 徐州市| 扶风县| 普定县| 涞水县| 台南市| 汝阳县| 周至县| 灌阳县| 威海市| 托克托县| 郁南县| 隆子县| 固安县| 大悟县| 长海县| 陆河县| 麟游县| 巩留县| 龙州县| 师宗县| 股票| 衡山县| 沽源县| 七台河市|