Golang 切片 常用方法

文章目录

下面的方法省略一些校验,如数组越界等,且都采用泛型(要求go版本 >= 1.18)

移除指定位置的元素

go 复制代码
package main

import (
	"fmt"
)

func Delete[T any](source []T, index int) []T {
	return append(source[:index], source[index+1:]...)
}

func main() {
	fmt.Println(Delete([]int{1, 2, 3, 4, 5}, 3)) //[1,2,3,5]
}

查找元素的位置

找到返回位置,找不到返回 -1
也可以用来判断某个元素是否存在,大于 -1 即存在

go 复制代码
package main

import (
	"fmt"
)

func Delete[T any](source []T, assert func(t T) bool) int {
	for index, item := range source {
		if assert(item) {
			return index
		}
	}

	return -1
}

func main() {
	fmt.Println(Delete([]int{1, 2, 3, 4, 5}, func(t int) bool {
		return t == 3
	}))
	// 2
}

查找最大最小的元素

go 复制代码
package main

import (
	"fmt"
)

func Find[T any](source []T, assert func(t1, t2 T) bool) T {
	max := source[0]
	for _, item := range source {
		if assert(max, item) {
			max = item
		}
	}
	return max
}

func main() {
	fmt.Println(Find([]int{1, 2, 22, 8, 11, 3, 4, 5}, func(t1, t2 int) bool {
		return t2 > t1
	})) //22

	fmt.Println(Find([]int{1, 2, 22, 8, 11, 3, 4, 5}, func(t1, t2 int) bool {
		return t2 < t1
	})) //1
}

去重

T 使用 comparable 是因为 map 需要一个可比较的类型

go 复制代码
package main

import "fmt"

func Uniq[T comparable](collection []T) []T {
	result := make([]T, 0, len(collection))
	seen := make(map[T]struct{}, len(collection))

	for _, item := range collection {
		if _, ok := seen[item]; ok {
			continue
		}

		seen[item] = struct{}{}
		result = append(result, item)
	}

	return result
}

func main() {
	fmt.Println(Uniq([]int{6, 7, 6, 5})) //[6,7,5]
}

使用 struct{}{} 是因为它不占内存

go 复制代码
package main

func main() {
	fmt.Println(unsafe.Sizeof(struct{}{})) // 0
	fmt.Println(unsafe.Sizeof(true))       // 1
}

随机打乱

这里引入了 i int64,这个是让他们的随机种子不一样,不然在 main中的 10次打印结果都一致

go 复制代码
package main

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

func random[T any](input []T, i int64) []T {
	rand.Seed(time.Now().Unix() + i)
	for i := len(input) - 1; i >= 0; i-- {
		index := rand.Intn(i + 1)
		input[index], input[i] = input[i], input[index]
	}
	return input
}

func main() {
	for i := 0; i < 10; i++ {
		fmt.Println(random([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, int64(i)))
	}

	//下面的结果都一样
	for i := 0; i < 10; i++ {
		fmt.Println(random([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, 0))
	}
}

排序

这里展示的是选择排序,可以更换其它排序算法

go 复制代码
package main

import "fmt"

func sort[T any](source []T, assert func(a, b T) bool) []T {
	for i := 0; i < len(source); i++ {
		for j := i + 1; j < len(source); j++ {
			if assert(source[i], source[j]) {
				source[j], source[i] = source[i], source[j]
			}
		}
	}
	return source
}

func main() {
	r := sort([]int{1, 4, 3, 9, 7, 8, 5}, func(a, b int) bool {
		return a < b
	})
	fmt.Println(r) //[9 8 7 5 4 3 1]
}

二维排序

在排序的基础上增加了一个 index(要比较的元素位置),根据二维index位置的元素大小,来决定一维的排序位置

go 复制代码
package main

import "fmt"

func TwoDimensionalSort[T any](source [][]T, index int, assert func(a, b T) bool) [][]T {
	for i := 0; i < len(source); i++ {
		for j := i + 1; j < len(source); j++ {
            //二维index位置上元素的比较
			if assert(source[i][index], source[j][index]) {
                //一维位置交换
				source[j], source[i] = source[i], source[j]
			}
		}
	}
	return source
}

func main() {
	result := TwoDimensionalSort([][]int{{1, 3, 5}, {6, 2, 3}, {5, 9, 1}}, 2, func(a, b int) bool {
		return a > b
	})
	fmt.Println(result) //[[5 9 1] [6 2 3] [1 3 5]]

	result = TwoDimensionalSort([][]int{{1, 3, 5}, {6, 2, 3}, {5, 9, 1}}, 1, func(a, b int) bool {
		return a > b
	})
	fmt.Println(result) //[[6 2 3] [1 3 5] [5 9 1]]
}

sort.Sort 排序

进阶版本使用泛型加 sor.Sort 处理,算法由 sort.Sort 实现,而我只需要实现它排序对象的接口即可,Len()返回元素数量,Less() 比较方式 i 是否要 排在 j 前面,Swap() 交换方式

go 复制代码
type Interface interface {
	// Len is the number of elements in the collection.
	Len() int

	// Less reports whether the element with index i
	// must sort before the element with index j.
	//
	// If both Less(i, j) and Less(j, i) are false,
	// then the elements at index i and j are considered equal.
	// Sort may place equal elements in any order in the final result,
	// while Stable preserves the original input order of equal elements.
	//
	// Less must describe a transitive ordering:
	//  - if both Less(i, j) and Less(j, k) are true, then Less(i, k) must be true as well.
	//  - if both Less(i, j) and Less(j, k) are false, then Less(i, k) must be false as well.
	//
	// Note that floating-point comparison (the < operator on float32 or float64 values)
	// is not a transitive ordering when not-a-number (NaN) values are involved.
	// See Float64Slice.Less for a correct implementation for floating-point values.
	Less(i, j int) bool

	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}
go 复制代码
package main

import (
	"fmt"
	"sort"
)

type SortStruct[T comparable] struct {
	Data   [][]T
	Assert func(a, b T) bool
	Index  int
}

func (s SortStruct[T]) Len() int {
	return len(s.Data)
}

func (s SortStruct[T]) Less(i, j int) bool {
	return s.Assert(s.Data[i][s.Index], s.Data[j][s.Index])
}

func (s SortStruct[T]) Swap(i, j int) {
	s.Data[i], s.Data[j] = s.Data[j], s.Data[i]
}

func main() {
	result := SortStruct[int]{
		Data: [][]int{
			{1, 2, 3},
			{3, 1, 2},
			{6, 7, 8},
		},
		Assert: func(a, b int) bool {
			return a < b
		},
		Index: 1,
	}
	sort.Sort(result)
	fmt.Println(result.Data) //[[3 1 2] [1 2 3] [6 7 8]]
}
相关推荐
卷无止境几秒前
零信任架构与传统边界安全:一场关于"信任"的根本分歧
后端
风止何安啊2 分钟前
我一个前端仔,居然用 Python 搞起了 AI?从零到一,撸了个 AI 聊天框小 demo
前端·人工智能·后端
思麟呀10 分钟前
C++11并发编程:call_once一次性执行+atomic原子类型+CAS无锁编程+自旋锁
linux·开发语言·jvm·c++·windows
逍遥运德14 分钟前
PostgreSQL ---【序列】用法详解
后端·sql·postgresql
码不停蹄的玄黓35 分钟前
Java 生产者-消费者模型详解
java·开发语言·python
爱讲故事的38 分钟前
操作系统第一讲复习:为什么学习操作系统,以及操作系统到底在做什么?
linux·开发语言·windows·学习·ubuntu·c#
笨蛋不要掉眼泪41 分钟前
Java并发编程:Executors框架类深度解析
java·开发语言·并发
回家路上绕了弯1 小时前
AgentScope Harness 深度实战:让Java智能体从“Demo可用”走向“生产可用”
后端
卷心菜投手ovo1 小时前
RAG 为什么引用总是对不上?
后端·github
foggyprojects1 小时前
动态 SQL 模板里,权限条件为什么要注入而不是散落在业务代码里
后端