{"id":13786668,"url":"https://github.com/psampaz/slice","last_synced_at":"2025-05-11T22:32:01.386Z","repository":{"id":82039879,"uuid":"224108831","full_name":"psampaz/slice","owner":"psampaz","description":"Type-safe functions for common Go slice operations","archived":false,"fork":false,"pushed_at":"2020-04-09T15:24:07.000Z","size":124,"stargazers_count":51,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-22T13:32:24.735Z","etag":null,"topics":["go","golang","slice-tricks","slices"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/psampaz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-11-26T05:20:39.000Z","updated_at":"2023-05-25T06:24:35.000Z","dependencies_parsed_at":"2023-04-04T16:46:48.915Z","dependency_job_id":null,"html_url":"https://github.com/psampaz/slice","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psampaz%2Fslice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psampaz%2Fslice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psampaz%2Fslice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psampaz%2Fslice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psampaz","download_url":"https://codeload.github.com/psampaz/slice/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213845574,"owners_count":15646795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","slice-tricks","slices"],"created_at":"2024-08-03T19:01:27.659Z","updated_at":"2024-08-03T19:06:32.068Z","avatar_url":"https://github.com/psampaz.png","language":"Go","readme":"![Build Status](https://github.com/psampaz/slice/workflows/build/badge.svg)\n[![codecov](https://codecov.io/gh/psampaz/slice/branch/master/graph/badge.svg)](https://codecov.io/gh/psampaz/slice)\n[![GoDoc](https://godoc.org/github.com/psampaz/slice?status.svg)](https://godoc.org/github.com/psampaz/slice)\n[![Go Report Card](https://goreportcard.com/badge/github.com/psampaz/slice)](https://goreportcard.com/report/github.com/psampaz/slice)\n[![golangci](https://golangci.com/badges/github.com/psampaz/slice.svg)](https://golangci.com/r/github.com/psampaz/slice)\n\nType-safe functions for common Go slice operations.\n\n# Installation\n\n```\ngo get github.com/psampaz/slice\n```\n\n# Operations \n\n✔ = Supported \n\n✕ = Non supported \n\n\\- = Not yet implemented\n\n|             | bool | byte | complex(all) | float(all) | int(all) | string | uint(all) | uintptr |\n| ----------- | ---- | ---- | ------------ | ---------- | -------- | ------ | --------- | ------- |\n| Batch       | -    | -    | -            | -          | -        | -      | -         | -       | \n| Contains    | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| Copy        | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| Deduplicate | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| Delete      | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| DeleteRange | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| Filter      | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       |\n| Insert      | -    | -    | -            | -          | -        | -      | -         | -       | \n| Max         | ✕    | ✔    | ✕            | ✔          | ✔        | ✕      | ✔         | ✔       |\n| Min         | ✕    | ✔    | ✕            | ✔          | ✔        | ✕      | ✔         | ✔       |\n| Pop         | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       |\n| Push        | -    | -    | -            | -          | -        | -      | -         | -       |\n| Reverse     | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| Shift       | -    | -    | -            | -          | -        | -      | -         | -       | \n| Shuffle     | ✔    | ✔    | ✔            | ✔          | ✔        | ✔      | ✔         | ✔       | \n| Sum         | ✕    | ✔    | ✔            | ✔          | ✔        | ✕      | ✔         | ✔       | \n| Unshift     | -    | -    | -            | -          | -        | -      | -         | -       | \n\n# Examples\n\n## slice.Deduplicate\n\nDeduplicate performs order preserving, in place deduplication of a slice\n```go\n    a := []int{1, 2, 3, 2, 5, 3}\n    a = slice.DeduplicateInt(a) // [1, 2, 3, 5]\n```\n\n## slice.Delete\n\nDelete removes an element at a specific index of a slice. An error is return in case the index is out of bounds or the slice is nil or empty.\n```go\n    a := []int{1, 2, 3, 4, 5}\n    a, err = slice.DeleteInt(a, 2) // [1, 2, 4, 5], nil\n```\n\n## slice.DeleteRange\n\nDeleteRange deletes the elements between from and to index (inclusive) from a slice. An error is return in case the index is out of bounds or the slice is nil or empty.\n```go\n    a := []int{1, 2, 3, 4, 5}\n    a, err = slice.DeleteRangeInt(a, 2, 3) // [1, 2, 5], nil\n```\n\n## slice.Contains\n\nContains checks if a specific value exists in a slice.\n```go\n    a := []int{1, 2, 3, 4, 5}\n    exists := slice.ContainsInt(a, 3) // true\n```\n\n## slice.Copy\n\nCopy creates a copy of a slice.\nThe resulting slice has the same elements as the original but the underlying array is different.\nSee https://github.com/go101/go101/wiki\n```go\n    a := []int{1, 2, 3, 4}\n    b := slice.CopyInt(a) // [1, 2, 3, 4]\n```\n\n## slice.Filter\n\nFilter performs in place filtering of a slice based on a predicate\n```go\n    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}\n    keep := func(x int) bool {\n        return x%2 == 0 \n    }\n    a = slice.FilterInt(a, keep) // [2, 4, 6, 8, 10]\n```\n\n## slice.Max\n\nMax returns the maximum value of a slice or an error in case of a nil or empty slice.\n```go\n    a := []int{1, 2, 3, 0, 4, 5}\n    max, err := slice.MaxInt(a) // 5, nil\n```\n\n## slice.Min\n\nMin returns the minimum value of a slice or an error in case of a nil or empty slice.\n```go\n    a := []int{1, 2, 3, 0, 4, 5}\n    min, err := slice.MinInt(a) // 0, nil\n```\n\n## slice.Pop\n\nPop removes and returns the last value a slice and the remaining slice. An error is returned in case of a nil or empty slice.\n```go\n    a := []int{1, 2, 3, 4, 5}\n    v, a, err := slice.PopInt(a) // 5, [1, 2, 3, 4], nil\n```\n\n## slice.Reverse\n\nReverse performs in place reversal of a slice\n```go\n    a := []int{1, 2, 3, 4, 5}\n    a = slice.ReverseInt(a) // [5, 4, 3, 2, 1]\n```\n\n## slice.Shuffle\n\nShuffle shuffles (in place) a slice\n```go\n    a := []int{1, 2, 3, 4, 5}\n    a = slice.ShuffleInt(a) // [3, 5, 1, 4, 2] (random output)\n ```\n\n## slice.Sum\n\nSum returns the sum of the values of a slice or an error in case of a nil or empty slice\n\n```go\n    a := []int{1, 2, 3}\n    sum, err := slice.SumInt(a) // 6, nil\n```\n\n# Tests\n\nif you want to run the test suite for this library:\n\n```go\n$ go test -v -cover\n```\n\n# Credits\n\n- SliceTricks (https://github.com/golang/go/wiki/SliceTricks). This was the inspiration behind this library.\n- Genny (https://github.com/cheekybits/genny). In order to speedup the development and avoid massive copy paste, the excellent Genny library was used.\n\n# Contributing\n\nYou are very welcome to contribute new operations or bug fixes in this library.\n\n## Contribution guidelines (code)\n\n1. Use only functions. This is a function based library so struct based operations will not be accepted, in order to preserve simplicity and consistency.\n\n2. If the operation is not working on a nil or empty slice, then the function should return an error.\n\n3. If the operation accepts slice indexes as parameters, then the function should guard against out of bound index values and return an error in that case.\n\n4. All operations should be in place operations, meaning that they should alter the original slice. \n\n5. Each function should have precise documentation. \n\n6. Each operation should live in each own file. Example:\n\n    ```\n    min.go\n    min_test.go\n    ```\n7. The naming convention for functions is OperationType. Example:\n\n    ``` \n    MinInt32()\n    ```\n\n    instead of \n\n    ``` \n    Int32Min()\n    ```\n8. Implement ALL applicable types in the same PR.\n\n9. Include one testable example for Int type at the end of the test file.\n\n10. Include one example in the Examples section of README\n\n11. Update the table in the Operation section of README \n\n12. Update the UNRELEASED section of CHANGELOG\n\n## Contribution guidelines (tests)\n\n1. All code should be 100% covered with tests\n2. All operations should be tested for 3 scenarios at least:\n    1. nil slice\n    2. empty slice\n    3. non empty slice\n\n## Static code analysis    \n\ngolangci.com runs on all PRs. Code is checked with golint, go vet, gofmt, plus 20+ linters, and review comments will be automatically added in your PR in case of a failure. You can see the whole list of linters here: https://golangci.com/product#linters\n\n## Steps for contributing new operations\n\n1. Open an issue describing the new operation, the proposed name and the applicable types.\n2. If the operation is approved to be included in the library, create a small PR the implementation and test for only only type. \n3. After code review you can proceed the implementation for the rest types. This is necessary because if you submit a PR with the implementation and test for all types, a small correction during review could eventually lead to a big refactor due to code duplication.\n\n## Using Genny for fast implementation of all types of an operation (Optional)\n\nThe following steps are an example of how to use [https://github.com/cheekybits/genny](Genny) to implement the min operation:\n\n1. Install Genny\n\n    ```\n    go get github.com/cheekybits/genny\n    ```\n\n2. Create a file named min_genny.go\n\n    ```go\n    package slice\n\n    import (\n        \"errors\"\n        \"github.com/cheekybits/genny/generic\"\n    )\n\n    type Type generic.Type\n\n    // MinType returns the minimum value of an Type slice or an error in case of a nil or empty slice\n    func MinType(a []Type) (Type, error) {\n        if len(a) == 0 {\n            return 0, errors.New(\"Cannot get the minimum of a nil or empty slice\")\n        }\n\n        min := a[0]\n        for k := 1; k \u003c len(a); k++ {\n            if a[k] \u003c min {\n                min = a[k]\n            }\n        }\n\n        return min, nil\n    }\n    ```\n\n3. Use genny to generate code for all Go's built in types:\n\n    ```\n    cat min_genny.go | genny gen Type=BUILTINS \u003e min.go\n    ```\n\n    This step will generate a file min.go with the following content:\n\n    ```go\n    package slice\n\n    import \"errors\"\n\n    // MinByte returns the minimum value of a byte slice or an error in case of a nil or empty slice\n    func MinByte(a []byte) (byte, error) {\n        if len(a) == 0 {\n            return 0, errors.New(\"Cannot get the minimum of a nil or empty slice\")\n        }\n\n        min := a[0]\n        for k := 1; k \u003c len(a); k++ {\n            if a[k] \u003c min {\n                min = a[k]\n            }\n        }\n\n        return min, nil\n    }\n\n    // MinFloat32 returns the minimum value of a float32 slice or an error in case of a nil or empty slice\n    func MinFloat32(a []float32) (float32, error) {\n        if len(a) == 0 {\n            return 0, errors.New(\"Cannot get the minimum of a nil or empty slice\")\n        }\n\n        min := a[0]\n        for k := 1; k \u003c len(a); k++ {\n            if a[k] \u003c min {\n                min = a[k]\n            }\n        }\n\n        return min, nil\n    }\n    .\n    .\n    .\n    .\n    ```\n\n4. Delete the implementation for all types not applicable for the operation\n\n5. Create a file named min_genny_test.go\n\n    ```go\n    package slice\n\n    import (\n        \"fmt\"\n        \"testing\"\n    )\n\n    func TestMinType(t *testing.T) {\n        type args struct {\n            a []Type\n        }\n        tests := []struct {\n            name    string\n            args    args\n            want    Type\n            wantErr bool\n        }{\n            {\n                name: \"nil slice\",\n                args: args{\n                    a: nil,\n                },\n                want:    0,\n                wantErr: true,\n            },\n            {\n                name: \"empty slice\",\n                args: args{\n                    a: []Type{},\n                },\n                want:    0,\n                wantErr: true,\n            },\n            {\n                name: \"non empty slice\",\n                args: args{\n                    a: []Type{1, 3, 2, 0, 5, 4},\n                },\n                want:    0,\n                wantErr: false,\n            },\n        }\n        for _, tt := range tests {\n            t.Run(tt.name, func(t *testing.T) {\n                got, err := MinType(tt.args.a)\n                if (err != nil) != tt.wantErr {\n                    t.Errorf(\"MinType() error = %v, wantErr %v\", err, tt.wantErr)\n                    return\n                }\n                if got != tt.want {\n                    t.Errorf(\"MinType() = %v, want %v\", got, tt.want)\n                }\n            })\n        }\n    }\n\n    ```\n\n6. Use genny to generate tests for all Go's built in types:\n\n    ```\n    cat min_genny_test.go | genny gen Type=BUILTINS \u003e min_test.go\n    ```\n\n    This step will generate a file min_test.go with tests for each one of Go's built in types.\n\n7. Remove tests for non applicable types.\n\n8. Adjust the tests for each one of the types.\n\n9. Delete min_genny.go and min_genny_test.go\n\n","funding_links":[],"categories":["工具库","Utilities","公用事业公司","工具库`可以提升效率的通用代码库和工具`","Utility"],"sub_categories":["查询语","Utility/Miscellaneous","实用程序/Miscellaneous","HTTP Clients","Fail injection"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsampaz%2Fslice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsampaz%2Fslice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsampaz%2Fslice/lists"}