collection

package module
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2020 License: MIT Imports: 10 Imported by: 59

README

collection

PkgGoDev Build and Test

Usage

Querying Collections

Inspired by .NET's Linq, querying data structures used in this library is a snap! Build Go pipelines quickly and easily which will apply lambdas as they query your data structures.

Slices

Converting between slices and a queryable structure is as trivial as it should be.

original := []interface{}{"a", "b", "c"}
subject := collection.AsEnumerable(original...)

for entry := range subject.Enumerate(nil) {
    fmt.Println(entry)
}
// Output:
// a
// b
// c

Where
subject := collection.AsEnumerable(1, 2, 3, 4, 5, 6)
filtered := collection.Where(subject, func(num interface{}) bool{
    return num.(int) > 3
})
for entry := range filtered.Enumerate(nil) {
    fmt.Println(entry)
}
// Output:
// 4
// 5
// 6
Select
subject := collection.AsEnumerable(1, 2, 3, 4, 5, 6)
updated := collection.Select(subject, func(num interface{}) interface{}{
    return num.(int) + 10
})
for entry := range updated.Enumerate(nil) {
    fmt.Println(entry)
}
// Output:
// 11
// 12
// 13
// 14
// 15
// 16

Queues

Creating a Queue
done := make(chan struct{})
subject := collection.NewQueue(1, 2, 3, 5, 8, 13, 21)
selected := subject.Enumerate(done).Skip(3).Take(3)
for entry := range selected {
	fmt.Println(entry)
}
close(done)
// Output:
// 5
// 8
// 13
Checking if a Queue is empty
populated := collection.NewQueue(1, 2, 3, 5, 8, 13)
notPopulated := collection.NewQueue()
fmt.Println(populated.IsEmpty())
fmt.Println(notPopulated.IsEmpty())
// Output:
// false
// true

Versioning

This library will conform to strict semantic versions as defined by semver.org's v2 specification.

Contributing

I accept contributions! To ensure glide users and go get users retrieve the same commit, please submit PRs to the 'dev' branch. Remember to add tests!

Documentation

Overview

Package collection seeks to provide an expressive and readable way of working with basic data structures in Go.

As a former .NET developer, I deeply missed writing programs in the style of Linq. Doing so enables concurrent/ parallel reactive programs to be written in a snap. Go's functional nature enables us to have a very similar, if more verbose, experience.

Take for example the scenario of printing the number of Go source files in a directory. Using this package, this takes only a few lines:

myDir := collection.Directory{
	Location: "./",
}

results := myDir.Enumerate(nil).Where(func(x interface{}) bool {
	return strings.HasSuffix(x.(string), ".go")
})

fmt.Println(results.CountAll())

A directory is a collection of filesystem entries, so we're able to iterate through them using the "Enumerate" function. From there, we filter on only file names that end with ".go". Finally, we print the number of entries that were encountered.

This is a trivial example, but imagine building more elaborate pipelines. Maybe take advantage of the `SelectParallel` function which allows multiple goroutines to process a single transform at once, with their results being funnelled into the next phase of the pipeline. Suddenly, injecting new steps can be transparent.

Index

Examples

Constants

View Source
const (
	DirectoryOptionsExcludeFiles = 1 << iota
	DirectoryOptionsExcludeDirectories
	DirectoryOptionsRecursive
)

These constants define all of the supported options for configuring a `Directory`

Variables

View Source
var (
	ErrUnexpectedType = errors.New("value was of an unexpected type")
)

A collection of errors that may be thrown by functions in this file.

Functions

func All added in v0.3.0

func All(subject Enumerable, p Predicate) bool

All tests whether or not all items present in an Enumerable meet a criteria.

func Any added in v0.2.0

func Any(iterator Enumerable) bool

Any tests an Enumerable to see if there are any elements present.

func Anyp added in v0.2.0

func Anyp(iterator Enumerable, p Predicate) bool

Anyp tests an Enumerable to see if there are any elements present that meet a criteria.

func Count added in v0.2.0

func Count(iter Enumerable, p Predicate) int

Count iterates over a list and keeps a running tally of the number of elements satisfy a predicate.

func CountAll added in v0.2.0

func CountAll(iter Enumerable) int

CountAll iterates over a list and keeps a running tally of how many it's seen.

func ElementAt added in v0.2.0

func ElementAt(iter Enumerable, n uint) interface{}

ElementAt retreives an item at a particular position in an Enumerator.

func First added in v0.3.0

func First(subject Enumerable) (retval interface{}, err error)

First retrieves just the first item in the list, or returns an error if there are no elements in the array.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	empty := collection.NewQueue()
	notEmpty := collection.NewQueue(1, 2, 3, 4)

	fmt.Println(collection.First(empty))
	fmt.Println(collection.First(notEmpty))

}
Output:

<nil> enumerator encountered no elements
1 <nil>

func IsErrorMultipleElements added in v0.3.2

func IsErrorMultipleElements(err error) bool

IsErrorMultipleElements determines whether or not the given error is the result of multiple values being returned when one or zero were expected.

func IsErrorNoElements added in v0.3.2

func IsErrorNoElements(err error) bool

IsErrorNoElements determines whethr or not the given error is the result of no values being returned when one or more were expected.

func Last added in v0.2.0

func Last(iter Enumerable) interface{}

Last retreives the item logically behind all other elements in the list.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewList(1, 2, 3, 4)
	fmt.Println(collection.Last(subject))
}
Output:

4

func Single added in v0.2.0

func Single(iter Enumerable) (retval interface{}, err error)

Single retreives the only element from a list, or returns nil and an error.

func Singlep added in v0.3.2

func Singlep(iter Enumerable, pred Predicate) (retval interface{}, err error)

Singlep retrieces the only element from a list that matches a criteria. If no match is found, or two or more are found, `Singlep` returns nil and an error.

func ToSlice added in v0.2.0

func ToSlice(iter Enumerable) []interface{}

ToSlice places all iterated over values in a Slice for easy consumption.

func UCount added in v0.2.0

func UCount(iter Enumerable, p Predicate) uint

UCount iterates over a list and keeps a running tally of the number of elements satisfy a predicate.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewStack(9, 'a', "str1")
	result := collection.UCount(subject, func(a interface{}) bool {
		_, ok := a.(string)
		return ok
	})
	fmt.Println(result)
}
Output:

1

func UCountAll added in v0.2.0

func UCountAll(iter Enumerable) uint

UCountAll iterates over a list and keeps a running tally of how many it's seen.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewStack(8, 9, 10, 11)
	fmt.Println(collection.UCountAll(subject))
}
Output:

4

Types

type Comparator

type Comparator func(a, b interface{}) (int, error)

Comparator is a function which evaluates two values to determine their relation to one another. - Zero is returned when `a` and `b` are equal. - Positive numbers are returned when `a` is greater than `b`. - Negative numbers are returned when `a` is less than `b`.

type Dictionary added in v1.0.0

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

Dictionary is a list of words. It is implemented as a Trie for memory efficiency.

func (*Dictionary) Add added in v1.0.0

func (dict *Dictionary) Add(word string) (wasAdded bool)

Add inserts a word into the dictionary, and returns whether or not that word was a new word.

Time complexity: O(m) where 'm' is the length of word.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := &collection.Dictionary{}

	const example = "hello"
	fmt.Println(subject.Contains(example))
	fmt.Println(subject.Size())
	subject.Add(example)
	fmt.Println(subject.Contains(example))
	fmt.Println(subject.Size())

}
Output:

false
0
true
1

func (*Dictionary) Clear added in v1.0.0

func (dict *Dictionary) Clear()

Clear removes all items from the dictionary.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := &collection.Dictionary{}

	subject.Add("hello")
	subject.Add("world")

	fmt.Println(subject.Size())
	fmt.Println(collection.CountAll(subject))

	subject.Clear()

	fmt.Println(subject.Size())
	fmt.Println(collection.Any(subject))

}
Output:

2
2
0
false

func (Dictionary) Contains added in v1.0.0

func (dict Dictionary) Contains(word string) bool

Contains searches the Dictionary to see if the specified word is present.

Time complexity: O(m) where 'm' is the length of word.

func (Dictionary) Enumerate added in v1.0.0

func (dict Dictionary) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate lists each word in the Dictionary alphabetically.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/marstr/collection"
)

func main() {
	subject := &collection.Dictionary{}
	subject.Add("world")
	subject.Add("hello")

	upperCase := collection.Select(subject, func(x interface{}) interface{} {
		return strings.ToUpper(x.(string))
	})

	for word := range subject.Enumerate(nil) {
		fmt.Println(word)
	}

	for word := range upperCase.Enumerate(nil) {
		fmt.Println(word)
	}

}
Output:

hello
world
HELLO
WORLD

func (*Dictionary) Remove added in v1.0.0

func (dict *Dictionary) Remove(word string) (wasRemoved bool)

Remove ensures that `word` is not in the Dictionary. Returns whether or not an item was removed.

Time complexity: O(m) where 'm' is the length of word.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	const world = "world"
	subject := &collection.Dictionary{}
	subject.Add("hello")
	subject.Add(world)

	fmt.Println(subject.Size())
	fmt.Println(collection.CountAll(subject))

	subject.Remove(world)

	fmt.Println(subject.Size())
	fmt.Println(collection.CountAll(subject))
	fmt.Println(collection.Any(subject))

}
Output:

2
2
1
1
true

func (Dictionary) Size added in v1.0.0

func (dict Dictionary) Size() int64

Size reports the number of words there are in the Dictionary.

Time complexity: O(1)

type Directory added in v0.3.3

type Directory struct {
	Location string
	Options  DirectoryOptions
}

Directory treats a filesystem path as a collection of filesystem entries, specifically a collection of directories and files.

func (Directory) Enumerate added in v0.3.3

func (d Directory) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate lists the items in a `Directory`

Example
traverser := Directory{
	Location: ".",
	Options:  DirectoryOptionsExcludeDirectories,
}

done := make(chan struct{})

filesOfInterest := traverser.Enumerate(done).Select(func(subject interface{}) (result interface{}) {
	cast, ok := subject.(string)
	if ok {
		result = path.Base(cast)
	} else {
		result = subject
	}
	return
}).Where(func(subject interface{}) bool {
	cast, ok := subject.(string)
	if !ok {
		return false
	}
	return cast == "filesystem_test.go"
})

for entry := range filesOfInterest {
	fmt.Println(entry.(string))
}
close(done)
Output:

filesystem_test.go

type DirectoryOptions added in v0.3.3

type DirectoryOptions uint

DirectoryOptions is a means of configuring a `Directory` instance to including various children in its enumeration without supplying a `Where` clause later.

type Enumerable

type Enumerable interface {
	Enumerate(cancel <-chan struct{}) Enumerator
}

Enumerable offers a means of easily converting into a channel. It is most useful for types where mutability is not in question.

var Empty Enumerable = &emptyEnumerable{}

Empty is an Enumerable that has no elements, and will never have any elements.

var Fibonacci Enumerable = fibonacciGenerator{}

Fibonacci is an Enumerable which will dynamically generate the fibonacci sequence.

func AsEnumerable added in v0.2.0

func AsEnumerable(entries ...interface{}) Enumerable

AsEnumerable allows for easy conversion of a slice to a re-usable Enumerable object.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	// When a single value is provided, and it is an array or slice, each value in the array or slice is treated as an enumerable value.
	original := []int{1, 2, 3, 4, 5}
	wrapped := collection.AsEnumerable(original)

	for entry := range wrapped.Enumerate(nil) {
		fmt.Print(entry)
	}
	fmt.Println()

	// When multiple values are provided, regardless of their type, they are each treated as enumerable values.
	wrapped = collection.AsEnumerable("red", "orange", "yellow", "green", "blue", "indigo", "violet")
	for entry := range wrapped.Enumerate(nil) {
		fmt.Println(entry)
	}
}
Output:

12345
red
orange
yellow
green
blue
indigo
violet

func Merge

func Merge(channels ...Enumerable) Enumerable

Merge takes the results as it receives them from several channels and directs them into a single channel.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	a := collection.AsEnumerable(1, 2, 4)
	b := collection.AsEnumerable(8, 16, 32)
	c := collection.Merge(a, b)
	sum := 0
	for x := range c.Enumerate(nil) {
		sum += x.(int)
	}
	fmt.Println(sum)

	product := 1
	for y := range a.Enumerate(nil) {
		product *= y.(int)
	}
	fmt.Println(product)
}
Output:

63
8

func ParallelSelect added in v0.3.0

func ParallelSelect(original Enumerable, operation Transform) Enumerable

ParallelSelect creates an Enumerable which will use all logically available CPUs to execute a Transform.

func Reverse added in v0.3.1

func Reverse(original Enumerable) Enumerable

Reverse will enumerate all values of an enumerable, store them in a Stack, then replay them all.

func Select added in v0.3.0

func Select(subject Enumerable, transform Transform) Enumerable

Select creates a reusable stream of transformed values.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	const offset = 'a' - 1

	subject := collection.AsEnumerable('a', 'b', 'c')
	subject = collection.Select(subject, func(a interface{}) interface{} {
		return a.(rune) - offset
	})

	fmt.Println(collection.ToSlice(subject))
}
Output:

[1 2 3]

func SelectMany added in v0.3.0

func SelectMany(subject Enumerable, toMany Unfolder) Enumerable

SelectMany allows for unfolding of values.

func Skip added in v0.3.0

func Skip(subject Enumerable, n uint) Enumerable

Skip creates a reusable stream which will skip the first `n` elements before iterating over the rest of the elements in an Enumerable.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	done := make(chan struct{})
	defer close(done)

	trimmed := collection.Take(collection.Skip(collection.Fibonacci, 1), 3)
	for entry := range trimmed.Enumerate(done) {
		fmt.Println(entry)
	}
}
Output:

1
1
2

func Take added in v0.3.0

func Take(subject Enumerable, n uint) Enumerable

Take retreives just the first `n` elements from an Enumerable.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	done := make(chan struct{})
	defer close(done)

	taken := collection.Take(collection.Fibonacci, 4)
	for entry := range taken.Enumerate(done) {
		fmt.Println(entry)
	}
}
Output:

0
1
1
2

func TakeWhile added in v0.3.0

func TakeWhile(subject Enumerable, criteria func(interface{}, uint) bool) Enumerable

TakeWhile creates a reusable stream which will halt once some criteria is no longer met.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	taken := collection.TakeWhile(collection.Fibonacci, func(x interface{}, n uint) bool {
		return x.(int) < 10
	})
	for entry := range taken.Enumerate(nil) {
		fmt.Println(entry)
	}
}
Output:

0
1
1
2
3
5
8

func Where added in v0.3.0

func Where(original Enumerable, p Predicate) Enumerable

Where creates a reusable means of filtering a stream.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	results := collection.Where(collection.AsEnumerable(1, 2, 3, 4, 5), func(a interface{}) bool {
		return a.(int) < 3
	})
	fmt.Println(collection.ToSlice(results))
}
Output:

[1 2]

type Enumerator

type Enumerator <-chan interface{}

Enumerator exposes a new syntax for querying familiar data structures.

func (Enumerator) All

func (iter Enumerator) All(p Predicate) bool

All tests whether or not all items present meet a criteria.

func (Enumerator) AsEnumerable added in v0.3.0

func (iter Enumerator) AsEnumerable() Enumerable

AsEnumerable stores the results of an Enumerator so the results can be enumerated over repeatedly.

func (Enumerator) Count

func (iter Enumerator) Count(p Predicate) int

Count iterates over a list and keeps a running tally of the number of elements satisfy a predicate.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable("str1", "str1", "str2")
	count1 := subject.Enumerate(nil).Count(func(a interface{}) bool {
		return a == "str1"
	})
	fmt.Println(count1)
}
Output:

2

func (Enumerator) CountAll

func (iter Enumerator) CountAll() int

CountAll iterates over a list and keeps a running tally of how many it's seen.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable('a', 'b', 'c', 'd', 'e')
	fmt.Println(subject.Enumerate(nil).CountAll())
}
Output:

5

func (Enumerator) Discard added in v0.3.0

func (iter Enumerator) Discard()

Discard reads an enumerator to the end but does nothing with it. This method should be used in circumstances when it doesn't make sense to explicitly cancel the Enumeration.

func (Enumerator) ElementAt

func (iter Enumerator) ElementAt(n uint) interface{}

ElementAt retreives an item at a particular position in an Enumerator.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	done := make(chan struct{})
	defer close(done)
	fmt.Print(collection.Fibonacci.Enumerate(done).ElementAt(4))
}
Output:

3

func (Enumerator) Last

func (iter Enumerator) Last() (retval interface{})

Last retreives the item logically behind all other elements in the list.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable(1, 2, 3)
	fmt.Print(subject.Enumerate(nil).Last())
}
Output:

3

func (Enumerator) Merge

func (iter Enumerator) Merge(others ...Enumerator) Enumerator

Merge takes the results of this Enumerator and others, and funnels them into a single Enumerator. The order of in which they will be combined is non-deterministic.

func (Enumerator) ParallelSelect added in v0.2.0

func (iter Enumerator) ParallelSelect(operation Transform) Enumerator

ParallelSelect will execute a Transform across all logical CPUs available to the current process.

func (Enumerator) Reverse

func (iter Enumerator) Reverse() Enumerator

Reverse returns items in the opposite order it encountered them in.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	a := collection.AsEnumerable(1, 2, 3).Enumerate(nil)
	a = a.Reverse()
	fmt.Println(a.ToSlice())
}
Output:

[3 2 1]

func (Enumerator) Select

func (iter Enumerator) Select(transform Transform) Enumerator

Select iterates over a list and returns a transformed item.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable('a', 'b', 'c').Enumerate(nil)
	const offset = 'a' - 1
	results := subject.Select(func(a interface{}) interface{} {
		return a.(rune) - offset
	})

	fmt.Println(results.ToSlice())
}
Output:

[1 2 3]

func (Enumerator) SelectMany added in v0.2.0

func (iter Enumerator) SelectMany(lister Unfolder) Enumerator

SelectMany allows for flattening of data structures.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {

	type BrewHouse struct {
		Name  string
		Beers collection.Enumerable
	}

	breweries := collection.AsEnumerable(
		BrewHouse{
			"Mac & Jacks",
			collection.AsEnumerable(
				"African Amber",
				"Ibis IPA",
			),
		},
		BrewHouse{
			"Post Doc",
			collection.AsEnumerable(
				"Prereq Pale",
			),
		},
		BrewHouse{
			"Resonate",
			collection.AsEnumerable(
				"Comfortably Numb IPA",
				"Lithium Altbier",
			),
		},
		BrewHouse{
			"Triplehorn",
			collection.AsEnumerable(
				"Samson",
				"Pepper Belly",
			),
		},
	)

	beers := breweries.Enumerate(nil).SelectMany(func(brewer interface{}) collection.Enumerator {
		return brewer.(BrewHouse).Beers.Enumerate(nil)
	})

	for beer := range beers {
		fmt.Println(beer)
	}

}
Output:

African Amber
Ibis IPA
Prereq Pale
Comfortably Numb IPA
Lithium Altbier
Samson
Pepper Belly

func (Enumerator) Skip

func (iter Enumerator) Skip(n uint) Enumerator

Skip retreives all elements after the first 'n' elements.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable(1, 2, 3, 4, 5, 6, 7)
	skipped := subject.Enumerate(nil).Skip(5)
	for entry := range skipped {
		fmt.Println(entry)
	}
}
Output:

6
7

func (Enumerator) Take

func (iter Enumerator) Take(n uint) Enumerator

Take retreives just the first 'n' elements from an Enumerator.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	done := make(chan struct{})
	defer close(done)

	taken := collection.Fibonacci.Enumerate(done).Skip(4).Take(2)
	for entry := range taken {
		fmt.Println(entry)
	}
}
Output:

3
5

func (Enumerator) TakeWhile

func (iter Enumerator) TakeWhile(criteria func(interface{}, uint) bool) Enumerator

TakeWhile continues returning items as long as 'criteria' holds true.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	taken := collection.Fibonacci.Enumerate(nil).TakeWhile(func(x interface{}, n uint) bool {
		return x.(int) < 6
	})
	for entry := range taken {
		fmt.Println(entry)
	}
}
Output:

0
1
1
2
3
5

func (Enumerator) Tee

func (iter Enumerator) Tee() (Enumerator, Enumerator)

Tee creates two Enumerators which will have identical contents as one another.

Example
package main

import (
	"fmt"
	"sync"

	"github.com/marstr/collection"
)

func main() {
	base := collection.AsEnumerable(1, 2, 4)
	left, right := base.Enumerate(nil).Tee()
	var wg sync.WaitGroup
	wg.Add(2)

	product := 1
	go func() {
		for x := range left {
			product *= x.(int)
		}
		wg.Done()
	}()

	sum := 0
	go func() {
		for x := range right {
			sum += x.(int)
		}
		wg.Done()
	}()

	wg.Wait()

	fmt.Printf("Sum: %d\n", sum)
	fmt.Printf("Product: %d\n", product)
}
Output:

Sum: 7
Product: 8

func (Enumerator) ToSlice

func (iter Enumerator) ToSlice() []interface{}

ToSlice places all iterated over values in a Slice for easy consumption.

func (Enumerator) UCount

func (iter Enumerator) UCount(p Predicate) uint

UCount iterates over a list and keeps a running tally of the number of elements satisfy a predicate.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable("str1", "str1", "str2")
	count1 := subject.Enumerate(nil).UCount(func(a interface{}) bool {
		return a == "str1"
	})
	fmt.Println(count1)
}
Output:

2

func (Enumerator) UCountAll

func (iter Enumerator) UCountAll() uint

UCountAll iterates over a list and keeps a running tally of how many it's seen.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.AsEnumerable('a', 2, "str1")
	fmt.Println(subject.Enumerate(nil).UCountAll())
}
Output:

3

func (Enumerator) Where

func (iter Enumerator) Where(predicate Predicate) Enumerator

Where iterates over a list and returns only the elements that satisfy a predicate.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	done := make(chan struct{})
	defer close(done)
	results := collection.Fibonacci.Enumerate(done).Where(func(a interface{}) bool {
		return a.(int) > 8
	}).Take(3)
	fmt.Println(results.ToSlice())
}
Output:

[13 21 34]

type LRUCache added in v1.1.0

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

LRUCache hosts up to a given number of items. When more are presented, the least recently used item is evicted from the cache.

Example
package main

import (
	"fmt"
	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLRUCache(3)
	subject.Put(1, "one")
	subject.Put(2, "two")
	subject.Put(3, "three")
	subject.Put(4, "four")
	fmt.Println(subject.Get(1))
	fmt.Println(subject.Get(4))
}
Output:

<nil> false
four true

func NewLRUCache added in v1.1.0

func NewLRUCache(capacity uint) *LRUCache

NewLRUCache creates an empty cache, which will accommodate the given number of items.

func (*LRUCache) Enumerate added in v1.1.0

func (lru *LRUCache) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate lists each value in the cache.

Example
package main

import (
	"context"
	"fmt"
	"github.com/marstr/collection"
)

func main() {
	ctx := context.Background()
	subject := collection.NewLRUCache(3)
	subject.Put(1, "one")
	subject.Put(2, "two")
	subject.Put(3, "three")
	subject.Put(4, "four")

	for key := range subject.Enumerate(ctx.Done()) {
		fmt.Println(key)
	}

}
Output:

four
three
two

func (*LRUCache) EnumerateKeys added in v1.1.0

func (lru *LRUCache) EnumerateKeys(cancel <-chan struct{}) Enumerator

EnumerateKeys lists each key in the cache.

Example
package main

import (
	"context"
	"fmt"
	"github.com/marstr/collection"
)

func main() {
	ctx := context.Background()
	subject := collection.NewLRUCache(3)
	subject.Put(1, "one")
	subject.Put(2, "two")
	subject.Put(3, "three")
	subject.Put(4, "four")

	for key := range subject.EnumerateKeys(ctx.Done()) {
		fmt.Println(key)
	}

}
Output:

4
3
2

func (*LRUCache) Get added in v1.1.0

func (lru *LRUCache) Get(key interface{}) (interface{}, bool)

Get retrieves a cached value, if it is still present.

func (*LRUCache) Put added in v1.1.0

func (lru *LRUCache) Put(key interface{}, value interface{})

Put adds a value to the cache. The added value may be expelled without warning.

func (*LRUCache) Remove added in v1.1.0

func (lru *LRUCache) Remove(key interface{}) bool

Remove explicitly takes an item out of the cache.

type LinkedList

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

LinkedList encapsulates a list where each entry is aware of only the next entry in the list.

func NewLinkedList

func NewLinkedList(entries ...interface{}) *LinkedList

NewLinkedList instantiates a new LinkedList with the entries provided.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject1 := collection.NewLinkedList('a', 'b', 'c', 'd', 'e')
	fmt.Println(subject1.Length())

	slice := []interface{}{1, 2, 3, 4, 5, 6}
	subject2 := collection.NewLinkedList(slice...)
	fmt.Println(subject2.Length())
}
Output:

5
6

func (*LinkedList) AddBack

func (list *LinkedList) AddBack(entry interface{})

AddBack creates an entry in the LinkedList that is logically at the back of the list.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList(2, 3, 5)
	subject.AddBack(8)
	result, _ := subject.PeekBack()
	fmt.Println(result)
	fmt.Println(subject.Length())
}
Output:

8
4

func (*LinkedList) AddFront

func (list *LinkedList) AddFront(entry interface{})

AddFront creates an entry in the LinkedList that is logically at the front of the list.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList(2, 3)
	subject.AddFront(1)
	result, _ := subject.PeekFront()
	fmt.Println(result)
}
Output:

1

func (*LinkedList) Enumerate

func (list *LinkedList) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate creates a new instance of Enumerable which can be executed on.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList(2, 3, 5, 8)
	results := subject.Enumerate(nil).Select(func(a interface{}) interface{} {
		return -1 * a.(int)
	})
	for entry := range results {
		fmt.Println(entry)
	}
}
Output:

-2
-3
-5
-8

func (*LinkedList) Get

func (list *LinkedList) Get(pos uint) (interface{}, bool)

Get finds the value from the LinkedList. pos is expressed as a zero-based index begining from the 'front' of the list.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList(2, 3, 5, 8)
	val, _ := subject.Get(2)
	fmt.Println(val)
}
Output:

5

func (*LinkedList) IsEmpty

func (list *LinkedList) IsEmpty() bool

IsEmpty tests the list to determine if it is populate or not.

func (*LinkedList) Length

func (list *LinkedList) Length() uint

Length returns the number of elements present in the LinkedList.

func (*LinkedList) PeekBack

func (list *LinkedList) PeekBack() (interface{}, bool)

PeekBack returns the entry logicall stored at the back of the list without removing it.

func (*LinkedList) PeekFront

func (list *LinkedList) PeekFront() (interface{}, bool)

PeekFront returns the entry logically stored at the front of this list without removing it.

func (*LinkedList) RemoveBack

func (list *LinkedList) RemoveBack() (interface{}, bool)

RemoveBack returns the entry logically stored at the back of this list and removes it.

func (*LinkedList) RemoveFront

func (list *LinkedList) RemoveFront() (interface{}, bool)

RemoveFront returns the entry logically stored at the front of this list and removes it.

func (*LinkedList) Sort

func (list *LinkedList) Sort(comparator Comparator) error

Sort rearranges the positions of the entries in this list so that they are ascending.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	// Sorti sorts into ascending order, this example demonstrates sorting
	// into descending order.
	subject := collection.NewLinkedList(2, 4, 3, 5, 7, 7)
	subject.Sort(func(a, b interface{}) (int, error) {
		castA, ok := a.(int)
		if !ok {
			return 0, collection.ErrUnexpectedType
		}
		castB, ok := b.(int)
		if !ok {
			return 0, collection.ErrUnexpectedType
		}

		return castB - castA, nil
	})
	fmt.Println(subject)
}
Output:

[7 7 5 4 3 2]

func (*LinkedList) Sorta

func (list *LinkedList) Sorta() error

Sorta rearranges the position of string entries in this list so that they are ascending.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList("charlie", "alfa", "bravo", "delta")
	subject.Sorta()
	for _, entry := range subject.ToSlice() {
		fmt.Println(entry.(string))
	}
}
Output:

alfa
bravo
charlie
delta

func (*LinkedList) Sorti

func (list *LinkedList) Sorti() (err error)

Sorti rearranges the position of integer entries in this list so that they are ascending.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList(7, 3, 2, 2, 3, 6)
	subject.Sorti()
	fmt.Println(subject)
}
Output:

[2 2 3 3 6 7]

func (*LinkedList) String

func (list *LinkedList) String() string

String prints upto the first fifteen elements of the list in string format.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject1 := collection.NewLinkedList()
	for i := 0; i < 20; i++ {
		subject1.AddBack(i)
	}
	fmt.Println(subject1)

	subject2 := collection.NewLinkedList(1, 2, 3)
	fmt.Println(subject2)
}
Output:

[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...]
[1 2 3]

func (*LinkedList) Swap

func (list *LinkedList) Swap(x, y uint) error

Swap switches the positions in which two values are stored in this list. x and y represent the indexes of the items that should be swapped.

Example
package main

import (
	"fmt"

	"github.com/marstr/collection"
)

func main() {
	subject := collection.NewLinkedList(2, 3, 5, 8, 13)
	subject.Swap(1, 3)
	fmt.Println(subject)
}
Output:

[2 8 5 3 13]

func (*LinkedList) ToSlice

func (list *LinkedList) ToSlice() []interface{}

ToSlice converts the contents of the LinkedList into a slice.

type List

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

List is a dynamically sized list akin to List in the .NET world, ArrayList in the Java world, or vector in the C++ world.

func NewList

func NewList(entries ...interface{}) *List

NewList creates a new list which contains the elements provided.

func (*List) Add

func (l *List) Add(entries ...interface{})

Add appends an entry to the logical end of the List.

func (*List) AddAt

func (l *List) AddAt(pos uint, entries ...interface{})

AddAt injects values beginning at `pos`. If multiple values are provided in `entries` they are placed in the same order they are provided.

Example
subject := NewList(0, 1, 4, 5, 6)
subject.AddAt(2, 2, 3)
fmt.Println(subject)
Output:

[0 1 2 3 4 5 6]

func (*List) Enumerate

func (l *List) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate lists each element present in the collection

func (*List) Get

func (l *List) Get(pos uint) (interface{}, bool)

Get retreives the value stored in a particular position of the list. If no item exists at the given position, the second parameter will be returned as false.

func (*List) IsEmpty

func (l *List) IsEmpty() bool

IsEmpty tests to see if this List has any elements present.

func (*List) Length

func (l *List) Length() uint

Length returns the number of elements in the List.

func (*List) Remove

func (l *List) Remove(pos uint) (interface{}, bool)

Remove retreives a value from this List and shifts all other values.

func (*List) Set

func (l *List) Set(pos uint, val interface{}) bool

Set updates the value stored at a given position in the List.

func (*List) String

func (l *List) String() string

String generates a textual representation of the List for the sake of debugging.

func (*List) Swap

func (l *List) Swap(x, y uint) bool

Swap switches the values that are stored at positions `x` and `y`

type Predicate

type Predicate func(interface{}) bool

Predicate defines an interface for funcs that make some logical test.

type Queue

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

Queue implements a basic FIFO structure.

func NewQueue

func NewQueue(entries ...interface{}) *Queue

NewQueue instantiates a new FIFO structure.

Example
empty := NewQueue()
fmt.Println(empty.Length())

populated := NewQueue(1, 2, 3, 5, 8, 13)
fmt.Println(populated.Length())
Output:

0
6

func (*Queue) Add

func (q *Queue) Add(entry interface{})

Add places an item at the back of the Queue.

Example
subject := &Queue{}
subject.Add(1)
subject.Add(2)
res, _ := subject.Peek()
fmt.Println(res)
Output:

1

func (*Queue) Enumerate added in v0.2.0

func (q *Queue) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate peeks at each element of this queue without mutating it.

func (*Queue) IsEmpty

func (q *Queue) IsEmpty() bool

IsEmpty tests the Queue to determine if it is populate or not.

Example
empty := NewQueue()
fmt.Println(empty.IsEmpty())

populated := NewQueue(1, 2, 3, 5, 8, 13)
fmt.Println(populated.IsEmpty())
Output:

true
false

func (*Queue) Length

func (q *Queue) Length() uint

Length returns the number of items in the Queue.

func (*Queue) Next

func (q *Queue) Next() (interface{}, bool)

Next removes and returns the next item in the Queue.

Example
subject := NewQueue(1, 2, 3, 5, 8, 13)
for !subject.IsEmpty() {
	val, _ := subject.Next()
	fmt.Println(val)
}
Output:

1
2
3
5
8
13

func (*Queue) Peek

func (q *Queue) Peek() (interface{}, bool)

Peek returns the next item in the Queue without removing it.

func (*Queue) ToSlice

func (q *Queue) ToSlice() []interface{}

ToSlice converts a Queue into a slice.

type Stack

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

Stack implements a basic FILO structure.

func NewStack

func NewStack(entries ...interface{}) *Stack

NewStack instantiates a new FILO structure.

Example
subject := NewStack(1, 2, 3)
for !subject.IsEmpty() {
	val, _ := subject.Pop()
	fmt.Println(val)
}
Output:

3
2
1

func (*Stack) Enumerate added in v0.2.0

func (stack *Stack) Enumerate(cancel <-chan struct{}) Enumerator

Enumerate peeks at each element in the stack without mutating it.

func (*Stack) IsEmpty

func (stack *Stack) IsEmpty() bool

IsEmpty tests the Stack to determine if it is populate or not.

func (*Stack) Peek

func (stack *Stack) Peek() (interface{}, bool)

Peek returns the entry at the top of the Stack without removing it.

func (*Stack) Pop

func (stack *Stack) Pop() (interface{}, bool)

Pop returns the entry at the top of the Stack then removes it.

func (*Stack) Push

func (stack *Stack) Push(entry interface{})

Push adds an entry to the top of the Stack.

func (*Stack) Size

func (stack *Stack) Size() uint

Size returns the number of entries populating the Stack.

type Transform added in v0.2.0

type Transform func(interface{}) interface{}

Transform defines a function which takes a value, and returns some value based on the original.

var Identity Transform = func(value interface{}) interface{} {
	return value
}

Identity is a trivial Transform which applies no operation on the value.

type Unfolder added in v0.3.0

type Unfolder func(interface{}) Enumerator

Unfolder defines a function which takes a single value, and exposes many of them as an Enumerator

Jump to

Keyboard shortcuts

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