tuple

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2024 License: Apache-2.0 Imports: 4 Imported by: 0

README

tuple

logo

A tuple "data type" for Go mimicking the API of Python tuples.

The aim was to keep the interface as simple as possible. On top of that to provide a type safe way to access elements without having to resort to struct types. Further, this library supports any number of items in the tuple. After the tuple has been created, it's immutable. It cannot be changed again.

Examples

Values
    t1 := tuple.New(1, 2, 3, 4)
    v := tuple.Value[int](t1, 1)
    fmt.Println(v) // 2 (int)

Note, that Value uses index to access elements and typed parameters to fetch the right type. It will panic if the value is NOT of the right type.

Also note that Value ISN'T on the Tuple! It's a package level function. The reason for that is to keep the interface and the tuple creation type free. If the Tuple creation had generics definitions it would mess with the rest of the functions. Thus, it was decided to leave the Value as a package function to have the benefit of generics.

If someone has a better ideas, PRs are welcome. ;)

Let's see Values with a nested Tuple.

    t1 := tuple.New(1, 2, 3, 4, tuple.New("1", "2"))
    v := tuple.Value[*Tuple](t1, 4)
    fmt.Println(v) // &Tuple{} with values "1", "2"
Range
	tuple1 := New(1, 2, "string")
	done := make(chan struct{})

	var result []any
	for v := range tuple1.Range(done) {
		result = append(result, v)
	}

	fmt.Println(result) // []any{1, 2, "string"}
Len
    tuple1 := New(1, 2, "string")
	fmt.Println(tuple1.Len()) // 3
Concatenate

You can add Tuples together.

	tuple1 := New(1, 2, 3, "string")
	tuple2 := New(4, 5, 6)

	result := Concat(tuple1, tuple2)

	fmt.Println(result) // []any{1, 2, 3, "string", 4, 5, 6}
Slice

Get a new Tuple for a subset of a Tuple. The original is unchanged.

	tuple1 := New(1, 2, 3, "string")

	result := tuple1.Slice(1, 3)

    fmt.Println(result) // &Tuple{values: []any{2, 3}}
ToSlice

Create a slice out of a Tuple.

	tuple := New(1, 2, 3, "string")

	fmt.Println(tuple.ToSlice()) // []any{1, 2, 3, "string"}

Concurrent safe

All tuple operations are using a Read sync mutex, thus should be safe for concurrent operations.

Python tuple feature parity

Python tuple features that have been implemented:

  • to slice
  • immutable once created
  • fixed number of items
  • ordered -> insertion order
  • tuples can be stored inside tuples
  • any number of items
  • indexable
  • threadsafe
  • sliceable
  • combinable
  • can be used as hash keys
  • range over

Hashing

Once a tuple is created it can be used as a key in a hash map. To use it as such do the following:

    t1 := tuple.New(1, 2, 3 ,4, tuple.New("5", "6", "7", "8"))
    t2 := tuple.New(1, 2, 3 ,4, tuple.New("5", "6", "7", "8"))
    m := make(map[uint64]struct{})
    m[t1.Key()] = struct{}{}
    m[t2.Key()] = struct{}{}
    // map[5075198087340781659:{}]
    
    t1 = tuple.New(1, 2, 3 ,4, tuple.New("5", "6", "7", "8"))
    t2 = tuple.New(1, 2, 3 ,4, tuple.New("10", "11", "12", "13"))
    m = make(map[uint64]struct{})
    m[t1.Key()] = struct{}{}
    m[t2.Key()] = struct{}{}
    // map[5075198087340781659:{} 15816401886143238155:{}]

Panics

This library panics on errors. This is to keep it simple. Also, it only panics on actual panics, such as, un-hashable types and index out of bounds errors.

Why use this at all?

That's an interesting question. I would argue, why not? The biggest sell point here, in my humble opinion, is that it has a hash value that can be used in a Map. I used this for various interesting operations on Advent Of Code problems.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Value

func Value[T any](t *Tuple, index int) (value T)

Value will panic if the index is out of range. This is to keep in-line with tuple logic. Defining a type makes sure we get the right type when accessing values.

Types

type Contract

type Contract interface {
	// ToSlice sadly in this case, they will have to do some type assertions.
	ToSlice() []any
	Len() int
	Slice(from, to int) *Tuple
	Key() uint64
	Range(done <-chan struct{}) chan any
}

Contract doesn't include Value function so the value getter can be generic and used for accessing elements of the Tuple in a generic way. In order to prevent having to define a type during creation and other operations Value will not be on the tuple but on the Package.

type Tuple

type Tuple struct {
	// contains filtered or unexported fields
}

Tuple contains the values within a tuple.

func Concat

func Concat(tuple ...*Tuple) *Tuple

Concat adds up tuples and creates a new resulting tuple with all values in order as they were created.

func New

func New(values ...any) *Tuple

New will create a new Tuple. The Tuple can be access by its API. Doing so is thread safe. You can embed Tuples into a Tuple. t := New(1, 2, 3, New(4, 5, 6)) t2 := t.Value(3)*Tuple -> a Tuple.

func (*Tuple) Key

func (t *Tuple) Key() uint64

Key returns a unique value for a given Tuple that can be used as a Key. The value is cached on the Tuple after the first call of this function and cannot be changed again.

func (*Tuple) Len

func (t *Tuple) Len() int

Len returns how many elements there are in the Tuple.

func (*Tuple) Range

func (t *Tuple) Range(done <-chan struct{}) chan any

Range provides a channel from which to fetch values of a tuple.

func (*Tuple) Slice

func (t *Tuple) Slice(from, to int) *Tuple

Slice returns a new tuple with the syntax [from: to]. It will panic in case of index out of bounds.

func (*Tuple) ToSlice

func (t *Tuple) ToSlice() []any

ToSlice creates a slice out of the tuple values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL