7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ありそうでないけど、あったらちょっと嬉しいGoのslice関数を作ってみた

7
Last updated at Posted at 2023-02-28

はじめに

Goを書いていて「sliceってもう少し組み込み関数あったら良いのに。。」と思うことありません??
僕はPHPを昔書いていたせいか、結構思います笑(PHPってarrayの組み込み関数豊富なんですよね。。)
もちろんslicesパッケージもあるのですが、ちょっと足りない。。足りないないならば作ってしまおう!
ということで、タイトルの通りGoのslice関数を作ってみました。
みなさんに「確かにちょっと嬉しい!」と思ってもらえたら、僕はめっちゃ嬉しいです!!

目次

環境
Go 1.19

sliceの各要素の数を数える

引数のsliceの各要素の数を数えます。

func CountValueSlice[T comparable](slices []T) map[T]int {
	resultMap := map[T]int{}
	for _, v := range slices {
		resultMap[v] += 1
	}
	return resultMap
}

例えばこんな感じで重複チェックとかにも使えそうと思ったり。。

main.go
	s := []string{"test1", "test2", "duplicate", "duplicate"}
	m := CountValueSlice(s)
	for k, v := range m {
		if v > 1 {
			fmt.Printf("%vは重複しています。", k) // duplicateは重複しています。
		}
	}

2つのsliceの差分を算出する

第1引数のsliceから第2引数のsliceを引き算するイメージです。
具体的には第1引数のsliceと第2引数のsliceに重複する要素を、第1引数のsliceから取り除きます。

func DiffSlice[T comparable](slice1, slice2 []T) []T {
	diffSlice := []T{}
	cmpMap := map[T]int{}

	// slice2が各要素が何個あるのかmapに格納
	for _, v := range slice2 {
		cmpMap[v] += 1
	}

	// slice2にある要素をslice1にあるか確認して、なければdiffSliceに格納
	for _, v := range slice1 {
		t, ok := cmpMap[v]
        // slice1の要素がslice2になければ、配列に格納
		if !ok {
		    diffSlice = append(diffSlice, v)
            continue
        }
        if t == 1 {
            delete(cmpMap, v)
        } else {
            cmpMap[v] -= 1
        }
	}
	return diffSlice
}

実際に処理するとこんな感じ。

main.go
func main() {
	slice1 := []int{1, 2, 3, 4, 5}
	slice2 := []int{1, 3, 5, 6}
	d := slices.DiffSlice(slice1, slice2)
	fmt.Println(d) // [2, 4]
}

複数のsliceをmergeする

2つのsliceをマージするだけなら、append関数で行けるのですが複数のsliceの場合はできないので作ってみました!
ただ、複数のsliceをマージしたい時があるかは別ですが笑

func MergeSlice[T any](slices ...[]T) []T {
	resultSlice := []T{}
	for _, v := range slices {
		resultSlice = append(resultSlice, v...)
	}
	return resultSlice
}

実際に動かすとこんな感じ。
まあこれはそんなに使う場面少ないかもですね笑

main.go
func main() {
	slice1 := []string{"a", "b"}
	slice2 := []string{"c", "d"}
	slice3 := []string{"e", "f"}
	slice4 := []string{"g", "h"}
	ms := slices.MergeSlice(slice1, slice2, slice3, slice4)
	fmt.Println(ms) // [a, b, c, d, e, f, g, h]
}

sliceの要素をフィルタリングする

第2引数の関数によって、フィルタリングします。

func FilterSlice[T any](slice []T, fn func(t T) bool) []T {
	resultSlice := []T{}
	for _, v := range slice {
		if fn(v) {
			resultSlice = append(resultSlice, v)
		}
	}
	return resultSlice
}

例えば、公開/非公開のステータスをもつDocumentがあって、今回は公開Documentを取り出したい、みたいな時使えそうかなと思ってます。

main.go
func main() {
	doc1 := Document{Name: "doc1", Status: Draft}
	doc2 := Document{Name: "doc2", Status: Draft}
	doc3 := Document{Name: "doc3", Status: Published}
	doc4 := Document{Name: "doc4", Status: Published}
	docs := []Document{doc1, doc2, doc3, doc4}
	fs := slices.FilterSlice(docs, func(t Document) bool {
		return t.Status.IsPublished()
	})
	fmt.Printf("公開中のdocumentは%+v", fs) // 公開中のdocumentは[{Name:doc3 Status:1} {Name:doc4 Status:1}]
}

type Document struct {
	Name   string
	Status DocStatus
}
type DocStatus int

const (
	Draft DocStatus = iota
	Published
)

func (ds DocStatus) IsPublished() bool {
	return ds == Published
}

sliceの要素を削除する

mapはdelete関数あるのに、sliceにはないのか。。と思い作りました笑

func DeleteValue[T comparable](slice []T, target T) []T {
	resultSlice := []T{}
	for _, v := range slice {
		if v != target {
			resultSlice = append(resultSlice, v)
		}
	}
	return resultSlice
}

使い方はシンプルでvalueを指定して、その要素を削除します。

main.go
func main() {
	is := []int{1, 2, 3, 4}
	ds := slices.DeleteValue(is, 3)
	fmt.Println(ds) // [1, 2, 4]
}

おわり

最後まで読んでいただきありがとうございました!
1つでもこれ使えそう!と思ってもらえたら嬉しいです!

一応githubでもソースコード公開してます。
https://github.com/hiroaki-u/go-pkg

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?