Type-safe functions for common Go slice operations

Build Status codecov GoDoc Go Report Card golangci

Type-safe functions for common Go slice operations.

Installation

go get github.com/psampaz/slice

Operations

= Supported

✕ = Non supported

- = Not yet implemented

bool byte complex(all) float(all) int(all) string uint(all) uintptr
Batch - - - - - - - -
Contains
Copy
Deduplicate
Delete
DeleteRange
Filter
Insert - - - - - - - -
Max
Min
Pop
Push - - - - - - - -
Reverse
Shift - - - - - - - -
Shuffle
Sum
Unshift - - - - - - - -

Examples

slice.Deduplicate

Deduplicate performs order preserving, in place deduplication of a slice

    a := []int{1, 2, 3, 2, 5, 3}
    a = slice.DeduplicateInt(a) // [1, 2, 3, 5]

slice.Delete

Delete 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.

    a := []int{1, 2, 3, 4, 5}
    a, err = slice.DeleteInt(a, 2) // [1, 2, 4, 5], nil

slice.DeleteRange

DeleteRange 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.

    a := []int{1, 2, 3, 4, 5}
    a, err = slice.DeleteRangeInt(a, 2, 3) // [1, 2, 5], nil

slice.Contains

Contains checks if a specific value exists in a slice.

    a := []int{1, 2, 3, 4, 5}
    exists := slice.ContainsInt(a, 3) // true

slice.Copy

Copy creates a copy of a slice. The resulting slice has the same elements as the original but the underlying array is different. See https://github.com/go101/go101/wiki

    a := []int{1, 2, 3, 4}
    b := slice.CopyInt(a) // [1, 2, 3, 4]

slice.Filter

Filter performs in place filtering of a slice based on a predicate

    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    keep := func(x int) bool {
        return x%2 == 0 
    }
    a = slice.FilterInt(a, keep) // [2, 4, 6, 8, 10]

slice.Max

Max returns the maximum value of a slice or an error in case of a nil or empty slice.

    a := []int{1, 2, 3, 0, 4, 5}
    max, err := slice.MaxInt(a) // 5, nil

slice.Min

Min returns the minimum value of a slice or an error in case of a nil or empty slice.

    a := []int{1, 2, 3, 0, 4, 5}
    min, err := slice.MinInt(a) // 0, nil

slice.Pop

Pop removes and returns the last value a slice and the remaining slice. An error is returned in case of a nil or empty slice.

    a := []int{1, 2, 3, 4, 5}
    v, a, err := slice.PopInt(a) // 5, [1, 2, 3, 4], nil

slice.Reverse

Reverse performs in place reversal of a slice

    a := []int{1, 2, 3, 4, 5}
    a = slice.ReverseInt(a) // [5, 4, 3, 2, 1]

slice.Shuffle

Shuffle shuffles (in place) a slice

    a := []int{1, 2, 3, 4, 5}
    a = slice.ShuffleInt(a) // [3, 5, 1, 4, 2] (random output)

slice.Sum

Sum returns the sum of the values of a slice or an error in case of a nil or empty slice

    a := []int{1, 2, 3}
    sum, err := slice.SumInt(a) // 6, nil

Tests

if you want to run the test suite for this library:

$ go test -v -cover

Credits

Contributing

You are very welcome to contribute new operations or bug fixes in this library.

Contribution guidelines (code)

  1. Use only functions. This is a function based library so struct based operations will not be accepted, in order to preserve simplicity and consistency.

  2. If the operation is not working on a nil or empty slice, then the function should return an error.

  3. 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.

  4. All operations should be in place operations, meaning that they should alter the original slice.

  5. Each function should have precise documentation.

  6. Each operation should live in each own file. Example:

    min.go
    min_test.go
    
  7. The naming convention for functions is OperationType. Example:

    MinInt32()
    

    instead of

    Int32Min()
    
  8. Implement ALL applicable types in the same PR.

  9. Include one testable example for Int type at the end of the test file.

  10. Include one example in the Examples section of README

  11. Update the table in the Operation section of README

  12. Update the UNRELEASED section of CHANGELOG

Contribution guidelines (tests)

  1. All code should be 100% covered with tests
  2. All operations should be tested for 3 scenarios at least:
    1. nil slice
    2. empty slice
    3. non empty slice

Static code analysis

golangci.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

Steps for contributing new operations

  1. Open an issue describing the new operation, the proposed name and the applicable types.
  2. If the operation is approved to be included in the library, create a small PR the implementation and test for only only type.
  3. 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.

Using Genny for fast implementation of all types of an operation (Optional)

The following steps are an example of how to use https://github.com/cheekybits/genny to implement the min operation:

  1. Install Genny

    go get github.com/cheekybits/genny
    
  2. Create a file named min_genny.go

    package slice
    
    import (
        "errors"
        "github.com/cheekybits/genny/generic"
    )
    
    type Type generic.Type
    
    // MinType returns the minimum value of an Type slice or an error in case of a nil or empty slice
    func MinType(a []Type) (Type, error) {
        if len(a) == 0 {
            return 0, errors.New("Cannot get the minimum of a nil or empty slice")
        }
    
        min := a[0]
        for k := 1; k < len(a); k++ {
            if a[k] < min {
                min = a[k]
            }
        }
    
        return min, nil
    }
  3. Use genny to generate code for all Go's built in types:

    cat min_genny.go | genny gen Type=BUILTINS > min.go
    

    This step will generate a file min.go with the following content:

    package slice
    
    import "errors"
    
    // MinByte returns the minimum value of a byte slice or an error in case of a nil or empty slice
    func MinByte(a []byte) (byte, error) {
        if len(a) == 0 {
            return 0, errors.New("Cannot get the minimum of a nil or empty slice")
        }
    
        min := a[0]
        for k := 1; k < len(a); k++ {
            if a[k] < min {
                min = a[k]
            }
        }
    
        return min, nil
    }
    
    // MinFloat32 returns the minimum value of a float32 slice or an error in case of a nil or empty slice
    func MinFloat32(a []float32) (float32, error) {
        if len(a) == 0 {
            return 0, errors.New("Cannot get the minimum of a nil or empty slice")
        }
    
        min := a[0]
        for k := 1; k < len(a); k++ {
            if a[k] < min {
                min = a[k]
            }
        }
    
        return min, nil
    }
    .
    .
    .
    .
  4. Delete the implementation for all types not applicable for the operation

  5. Create a file named min_genny_test.go

    package slice
    
    import (
        "fmt"
        "testing"
    )
    
    func TestMinType(t *testing.T) {
        type args struct {
            a []Type
        }
        tests := []struct {
            name    string
            args    args
            want    Type
            wantErr bool
        }{
            {
                name: "nil slice",
                args: args{
                    a: nil,
                },
                want:    0,
                wantErr: true,
            },
            {
                name: "empty slice",
                args: args{
                    a: []Type{},
                },
                want:    0,
                wantErr: true,
            },
            {
                name: "non empty slice",
                args: args{
                    a: []Type{1, 3, 2, 0, 5, 4},
                },
                want:    0,
                wantErr: false,
            },
        }
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
                got, err := MinType(tt.args.a)
                if (err != nil) != tt.wantErr {
                    t.Errorf("MinType() error = %v, wantErr %v", err, tt.wantErr)
                    return
                }
                if got != tt.want {
                    t.Errorf("MinType() = %v, want %v", got, tt.want)
                }
            })
        }
    }
  6. Use genny to generate tests for all Go's built in types:

    cat min_genny_test.go | genny gen Type=BUILTINS > min_test.go
    

    This step will generate a file min_test.go with tests for each one of Go's built in types.

  7. Remove tests for non applicable types.

  8. Adjust the tests for each one of the types.

  9. Delete min_genny.go and min_genny_test.go

Comments
  • add Pop operation

    add Pop operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Delete operation

    add Delete operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add DeleteRange operation

    add DeleteRange operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Sum operation

    add Sum operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Shuffle operation

    add Shuffle operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [ ] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Filter operation

    add Filter operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Reverse operation

    add Reverse operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Copy operation

    add Copy operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [ ] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Deduplicate operation

    add Deduplicate operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Contains operation

    add Contains operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • add Max operation

    add Max operation

    Make sure that you've checked the boxes below before you submit PR that adds a new operation:

    • [x] I implemented the operation for all applicable types
    • [x] I put all code in a seperate .go file named after the operation
    • [x] I included tests for all functions
    • [x] I documented all functions
    • [x] I named all functions using the OperationType convention. For example MinInt32 instead of Int32Min
    • [x] I included one testable example at the end of the test file
    • [x] I added a simple example in the Example section of Readme
    • [x] I updated the Operations section of Readme

    Thanks for your PR, you're awesome! :+1:

  • 希望列表能指定 index 去 pop(Strong hope to add args:index to pop method)

    希望列表能指定 index 去 pop(Strong hope to add args:index to pop method)

    非常喜欢你的项目,单却无法实际用到我的项目中,因为缺了一些实用的函数。希望 slice 能根据 idx 来 pop 出元素~ Very very like your project, but sadly cant use in my project cause missing some useful method. hoping can pop slice elem by index ~

Generate type-safe Go converters by simply defining an interface

goverter a "type-safe Go converter" generator goverter is a tool for creating type-safe converters. All you have to do is create an interface and exec

Jan 4, 2023
Type-safe atomic values for Go

Type-safe atomic values for Go One issue with Go's sync/atomic package is that there is no guarantee from the type system that operations on an intege

Apr 8, 2022
[TOOL, CLI] - Filter and examine Go type structures, interfaces and their transitive dependencies and relationships. Export structural types as TypeScript value object or bare type representations.

typex Examine Go types and their transitive dependencies. Export results as TypeScript value objects (or types) declaration. Installation go get -u gi

Dec 6, 2022
Some helper types for go1: priority queue, slice wrapper.

go-villa Package villa contains some helper types for Go: priority queue, slice wrapper, binary-search, merge-sort. GoDoc Link: http://godoc.org/githu

Apr 24, 2021
Go 1.18 Generics based slice package

The missing slice package A Go-generics (Go 1.18) based functional library with no side-effects that adds the following functions to a slice package:

Jan 8, 2023
Simple example program using CRUD operations to interface with azcosmos

Simple example program using CRUD operations to interface with azcosmos

Nov 15, 2021
Go library for Common Lisp format style output

format This library has the goal to bring the Common Lisp format directive to Go. This is work-in-progress, see the summary implementation table below

Jul 7, 2020
Shared library of common DTOs for Neo

Shared library of common DTOs for Neo

Dec 20, 2021
Toy program for benchmarking safe and unsafe ways of saving a file

save-a-file benchmarks the many strategies an editor could use to save a file. Example output on a SSD: ext4: $ ./save-a-file ~/tmp/foo 29.195µs per s

Jan 4, 2023
Start of a project that would let people stay informed about safe running spaces in their area.

SafeRun Start of a project that would let people stay informed about safe running spaces in their area. Too many people I'm friends with feel unsafe w

Feb 11, 2022
Analyze the binary outputted by `go build` to get type information etc.

Analyze the binary outputted by go build to get type information etc.

Oct 5, 2022
IBus Engine for GoVarnam. An easy way to type Indian languages on GNU/Linux systems.

IBus Engine For GoVarnam An easy way to type Indian languages on GNU/Linux systems. goibus - golang implementation of libibus Thanks to sarim and haun

Feb 10, 2022
Lithia is an experimental functional programming language with an implicit but strong and dynamic type system.

Lithia is an experimental functional programming language with an implicit but strong and dynamic type system. Lithia is designed around a few core concepts in mind all language features contribute to.

Dec 24, 2022
A tool to generate Pulumi Package schemas from Go type definitions

MkSchema A tool to generate Pulumi Package schemas from Go type definitions. This tool translates annotated Go files into Pulumi component schema meta

Sep 1, 2022
Haskell-flavoured functions for Go :smiley:

Hasgo Coverage status: gocover.io Our report card: Hasgo is a code generator with functions influenced by Haskell. It comes with some types out-of-the

Dec 25, 2022
Functional programming library for Go including a lazy list implementation and some of the most usual functions.

functional A functional programming library including a lazy list implementation and some of the most usual functions. import FP "github.com/tcard/fun

May 21, 2022
A simple Cron library for go that can execute closures or functions at varying intervals, from once a second to once a year on a specific date and time. Primarily for web applications and long running daemons.

Cron.go This is a simple library to handle scheduled tasks. Tasks can be run in a minimum delay of once a second--for which Cron isn't actually design

Dec 17, 2022
Set of functions/methods that will ease GO code generation

Set of functions/methods that will ease GO code generation

Dec 1, 2021
Some convenient string functions.

str Some convenient string functions. What This package containsa couple of functions to remove duplicates from string slices and optionally sort them

Dec 27, 2021