stream

package module
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Dec 8, 2020 License: MIT Imports: 5 Imported by: 3

README

Go Stream

PkgGoDev Go Report Card Build Status codecov

Go Stream, like Java 8 Stream.

Blog Post: https://youthlin.com/?p=1755

How to get

go get github.com/youthlin/stream

国内镜像: https://gitee.com/youthlin/stream
go.mod 中引入模块路径 github.com/youthlin/stream 及版本后,
再添加 replace 即可:

// go.mod

require github.com/youthlin/stream latest

replace github.com/youthlin/stream latest => gitee.com/youthlin/stream latest

Play online

https://play.golang.org/p/nPQJYqA3-Jr

package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	m := stream.IntRange(0, 10).
		Filter(func(e types.T) bool {
			return e.(int)%2 == 0
		}).
		Map(func(e types.T) types.R {
			return e.(int) * 2
		}).
		ReduceWith(map[int]string{}, func(acc types.R, e types.T) types.R {
			m := acc.(map[int]string)
			m[e.(int)] = fmt.Sprintf("<%d>", e)
			return m
		})
	fmt.Println(m)
	// Output:
	// map[0:<0> 4:<4> 8:<8> 12:<12> 16:<16>]
}

Examples


type Stream interface {
	// stateless operate 无状态操作

	Filter(types.Predicate) Stream         // 过滤
	Map(types.Function) Stream             // 转换
	FlatMap(func(t types.T) Stream) Stream // 打平
	Peek(types.Consumer) Stream            // peek 每个元素

	// stateful operate 有状态操作

	Distinct(types.IntFunction) Stream // 去重
	Sorted(types.Comparator) Stream    // 排序
	Limit(int64) Stream                // 限制个数
	Skip(int64) Stream                 // 跳过个数

	// terminal operate 终止操作

	// 遍历
	ForEach(types.Consumer)
	// return []T 转为切片
	ToSlice() []types.T
	// return []X which X is the type of some
	ToElementSlice(some types.T) types.R
	// return []X which X is same as the `typ` representation
	ToSliceOf(typ reflect.Type) types.R
	// 测试是否所有元素满足条件
	AllMatch(types.Predicate) bool
	// 测试是否没有元素满足条件
	NoneMatch(types.Predicate) bool
	// 测试是否有任意元素满足条件
	AnyMatch(types.Predicate) bool
	// Reduce return optional.Empty if no element. calculate result by (T, T) -> T from first element
	Reduce(accumulator types.BinaryOperator) optional.Optional
	// type of initValue is same as element.  (T, T) -> T
	ReduceFrom(initValue types.T, accumulator types.BinaryOperator) types.T
	// type of initValue is different from element. (R, T) -> R
	ReduceWith(initValue types.R, accumulator func(types.R, types.T) types.R) types.R
	FindFirst() optional.Optional
	// 返回元素个数
	Count() int64
}


func ExampleOf() {
	fmt.Println(stream.Of().Count())
	fmt.Println(stream.Of(1).Count())
	fmt.Println(stream.Of("a", "b").Count())
	var s = []int{1, 2, 3, 4}
	stream.Of(stream.Slice(s)...).ForEach(func(t types.T) {
		fmt.Printf("%d,", t)
	})
	// Output:
	// 0
	// 1
	// 2
	// 1,2,3,4,
}

func ExampleOfSlice() {
	var intArr = []int{1, 2, 3, 4}
	stream.OfSlice(intArr).ForEach(func(e types.T) {
		fmt.Printf("%d,", e)
	})
	var nilArr []int
	stream.OfSlice(nilArr).ForEach(func(e types.T) {
		fmt.Printf("should not print")
	})
	var strArr = []string{"a", "b"}
	stream.OfSlice(strArr).
		Map(func(e types.T) types.R {
			return fmt.Sprintf("<%s>", e)
		}).
		ForEach(func(e types.T) {
			fmt.Printf("%s,", e)
		})
	// Output:
	// 1,2,3,4,<a>,<b>,
}

func ExampleOfMap() {
	var m1 = map[int]string{
		3: "c",
		2: "b",
		1: "a",
	}
	s := stream.OfMap(m1).
		Map(func(e types.T) types.R {
			p := e.(types.Pair)
			p.First, p.Second = p.Second, p.First
			return p
		}).
		Sorted(func(left types.T, right types.T) int {
			p1 := left.(types.Pair)
			p2 := right.(types.Pair)
			return p1.Second.(int) - p2.Second.(int)
		}).
		ToSlice()
	fmt.Println(s)
	stream.OfMap(nil).ForEach(func(e types.T) {
		fmt.Println("not print")
	})
	// Output:
	// [{a 1} {b 2} {c 3}]
}

func ExampleStream_Filter() {
	stream.Of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).
		Filter(func(e types.T) bool {
			return e.(int)%3 == 0
		}).
		ForEach(func(e types.T) {
			fmt.Println(e)
		})
	// Output:
	// 0
	// 3
	// 6
	// 9
}
func ExampleStream_Map() {
	stream.IntRange(0, 5).
		Map(func(t types.T) types.R {
			return fmt.Sprintf("<%d>", t.(int))
		}).
		ForEach(func(t types.T) {
			fmt.Printf("%v", t)
		})
	// Output:
	// <0><1><2><3><4>
}
func ExampleStream_FlatMap() {
	stream.Of([]int{0, 2, 4, 6, 8}, []int{1, 3, 5, 7, 9}).
		FlatMap(func(t types.T) stream.Stream {
			return stream.Of(stream.Slice(t)...)
		}).
		ForEach(func(t types.T) {
			fmt.Printf("%d", t)
		})
	// Output:
	// 0246813579
}
func ExampleStream_Sorted() {
	stream.IntRange(1, 10).
		Sorted(types.ReverseOrder(types.IntComparator)).
		ForEach(func(t types.T) {
			fmt.Printf("%d,", t)
		})
	// Output:
	// 9,8,7,6,5,4,3,2,1,
}
func TestToMap(t *testing.T) {
	m := stream.IntRange(0, 10).ReduceWith(make(map[int]int), func(acc types.R, t types.T) types.R {
		acc.(map[int]int)[t.(int)] = t.(int) * 10
		return acc
	})
	t.Log(m)
	// Output:
	// map[0:0 1:10 2:20 3:30 4:40 5:50 6:60 7:70 8:80 9:90]
}

Change Log

  • v0.0.3 2020-12-08 add factory method: OfInts, OfInt64s, OfFloat32s, OfFloat64s, OfStrings;
    add Stream method: ReduceBy
  • v0.0.2 2020-12-07 add factory method: OfSlice, OfMap
  • v0.0.1 2020-11-12 first version

Todo

  • add Benchmark test
  • support parallel stream

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotSlice a error to panic when call Slice but argument is not slice
	ErrNotSlice = errors.New("not slice")
	ErrNotMap   = errors.New("not map")
)

Functions

func Entries added in v0.0.2

func Entries(mapValue types.T) []types.Pair

Entries 把任意的 map 类型转为 []Pair Entries return entries of a map as []types.Pair which `First` field is key, `Second` field is value

Example
package main

import (
	"fmt"
	"sort"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var m1 = map[int]string{
		1: "a",
		2: "b",
		3: "c",
	}
	entries := stream.Entries(m1)
	sort.Slice(entries, func(i, j int) bool {
		return entries[i].First.(int) < entries[j].First.(int)
	})
	fmt.Printf("%v\n", entries)
	stream.Of(stream.Slice(entries)...).ReduceWith(map[string]int{}, func(acc types.R, e types.T) types.R {
		pair := e.(types.Pair)
		(acc.(map[string]int))[pair.Second.(string)] = pair.First.(int)
		return acc
	})
}
Output:

[{1 a} {2 b} {3 c}]

func Slice

func Slice(slice types.T) []types.T

Slice 把任意的切片类型转为[]T类型. 可用作 Of() 入参. Slice convert any slice type to []types.T e.g. []int -> []types.T. may used with Of(). Note: cannot use ints (type []int) as type []types.T in argument to streams.Of

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
)

func main() {
	var ints = []int{1, 2, 3}
	fmt.Printf("%#v\n", stream.Slice(ints))
	var str = []string{"abc", "###"}
	fmt.Printf("%#v\n", stream.Slice(str))
}
Output:

[]types.T{1, 2, 3}
[]types.T{"abc", "###"}

Types

type Sortable

type Sortable struct {
	List []types.T
	Cmp  types.Comparator
}

Sortable use types.Comparator to sort []types.T 可以使用指定的 cmp 比较器对 list 进行排序 see sort.Interface

func (*Sortable) Len

func (a *Sortable) Len() int

func (*Sortable) Less

func (a *Sortable) Less(i, j int) bool

func (*Sortable) Swap

func (a *Sortable) Swap(i, j int)

type Stream

type Stream interface {
	Filter(types.Predicate) Stream         // 过滤
	Map(types.Function) Stream             // 转换
	FlatMap(func(t types.T) Stream) Stream // 打平
	Peek(types.Consumer) Stream            // peek 每个元素

	Distinct(types.IntFunction) Stream // 去重
	Sorted(types.Comparator) Stream    // 排序
	Limit(int64) Stream                // 限制个数
	Skip(int64) Stream                 // 跳过个数

	// 遍历
	ForEach(types.Consumer)
	// return []T 转为切片
	ToSlice() []types.T
	// return []X which X is the type of some
	ToElementSlice(some types.T) types.R
	// return []X which X is same as the `typ` representation
	ToSliceOf(typ reflect.Type) types.R
	// 测试是否所有元素满足条件
	AllMatch(types.Predicate) bool
	// 测试是否没有元素满足条件
	NoneMatch(types.Predicate) bool
	// 测试是否有任意元素满足条件
	AnyMatch(types.Predicate) bool
	// Reduce return optional.Empty if no element. calculate result by (T, T) -> T from first element, panic if reduction is nil
	Reduce(accumulator types.BinaryOperator) optional.Optional
	// type of initValue is same as element.  (T, T) -> T
	ReduceFrom(initValue types.T, accumulator types.BinaryOperator) types.T
	// type of initValue is different from element. (R, T) -> R
	ReduceWith(initValue types.R, accumulator func(acc types.R, e types.T) types.R) types.R
	// ReduceBy use `buildInitValue` to build the initValue, which parameter is a int64 means element size, or -1 if unknown size.
	// Then use `accumulator` to add each element to previous result
	ReduceBy(buildInitValue func(sizeMayNegative int64) types.R, accumulator func(acc types.R, e types.T) types.R) types.R
	FindFirst() optional.Optional
	// 返回元素个数
	Count() int64
}

Stream is a interface which holds all supported operates. It has stateless operates(Filter, Map, FlatMap, Peek), stateful operates(Distinct, Sorted, Limit, Skip), and the left methods are terminal operates.

func Generate

func Generate(get types.Supplier) Stream

Generate generates a infinite Stream which each element is generate by Supplier

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	// fibonacci 斐波那契数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368
	var fibonacci = func() types.Supplier {
		// -1 1 【0】 1 1 2 3
		a := -1
		b := 1
		return func() types.T {
			n := a + b
			a = b
			b = n
			return n
		}
	}
	stream.Generate(fibonacci()).Limit(20).ForEach(func(t types.T) {
		fmt.Printf("%d,", t)
	})
}
Output:

0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,

func Int64Range

func Int64Range(fromInclude, toExclude int64) Stream

Int64Range like IntRange

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.Int64Range(int64(0), int64(10)).ForEach(func(t types.T) {
		fmt.Printf("%d", t)
	})
}
Output:

0123456789

func Int64RangeStep

func Int64RangeStep(fromInclude, toExclude int64, step int) Stream

Int64RangeStep like IntRangeStep

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.Int64RangeStep(int64(0), int64(10), 3).ForEach(func(t types.T) {
		fmt.Printf("%d", t)
	})
}
Output:

0369

func IntRange

func IntRange(fromInclude, toExclude int) Stream

IntRange creates a Stream which element is the given range

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.IntRange(0, 5).
		ForEach(func(t types.T) {
			fmt.Println(t)
		})
}
Output:

0
1
2
3
4

func IntRangeStep

func IntRangeStep(fromInclude, toExclude, step int) Stream

IntRangeStep creates a Stream which element is the given range by step

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.IntRangeStep(0, 10, 2).ForEach(func(t types.T) {
		fmt.Println(t)
	})
}
Output:

0
2
4
6
8
Example (NegStep)
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.IntRangeStep(5, 0, -1).ForEach(func(t types.T) {
		fmt.Printf("%d,", t)
	})
}
Output:

5,4,3,2,1,
Example (ZeroStep)
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.IntRangeStep(0, 5, 0).
		Limit(10).ForEach(func(t types.T) {
		fmt.Printf("%d,", t)
	})
}
Output:

0,0,0,0,0,0,0,0,0,0,

func Iterate

func Iterate(seed types.T, operator types.UnaryOperator) Stream

Iterate create a Stream by a seed and an UnaryOperator

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	// 0   1   1   2 3 5 8
	// |   |  next
	// |   \curr(start)
	// \prev
	var prev = 0
	stream.Iterate(1, func(t types.T) types.T {
		curr := t.(int)
		next := prev + curr
		prev = curr
		return next
	}).
		Limit(6).
		ForEach(func(t types.T) {
			fmt.Printf("%d,", t)
		})
}
Output:

1,1,2,3,5,8,

func Of

func Of(elements ...types.T) Stream

Of create a Stream from some element It's recommend to pass pointer type cause the element may be copy at each operate

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	fmt.Println(stream.Of().Count())
	fmt.Println(stream.Of(1).Count())
	fmt.Println(stream.Of("a", "b").Count())
	var s = []int{1, 2, 3, 4}
	stream.Of(stream.Slice(s)...).ForEach(func(t types.T) {
		fmt.Printf("%d,", t)
	})
}
Output:

0
1
2
1,2,3,4,

func OfFloat32s added in v0.0.3

func OfFloat32s(element ...float32) Stream
Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var ints = []float32{1, 2, 3, 4}
	stream.OfFloat32s(ints...).ForEach(func(e types.T) {
		fmt.Printf("%v(%T),", e, e)
	})
}
Output:

1(float32),2(float32),3(float32),4(float32),

func OfFloat64s added in v0.0.3

func OfFloat64s(element ...float64) Stream
Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var ints = []float64{1, 2, 3, 4}
	stream.OfFloat64s(ints...).ForEach(func(e types.T) {
		fmt.Printf("%v(%T),", e, e)
	})
}
Output:

1(float64),2(float64),3(float64),4(float64),

func OfInt64s added in v0.0.3

func OfInt64s(element ...int64) Stream
Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var ints = []int64{1, 2, 3, 4}
	stream.OfInt64s(ints...).ForEach(func(e types.T) {
		fmt.Printf("%d(%T),", e, e)
	})
}
Output:

1(int64),2(int64),3(int64),4(int64),

func OfInts added in v0.0.3

func OfInts(element ...int) Stream
Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var ints = []int{1, 2, 3, 4}
	stream.OfInts(ints...).ForEach(func(e types.T) {
		fmt.Printf("%d,", e)
	})
}
Output:

1,2,3,4,

func OfMap added in v0.0.2

func OfMap(mapValue types.T) Stream

OfMap return a Stream which element type is types.Pair. the input parameter `mapValue` must be a map or it will panic if mapValue is nil, return a empty Stream ( same as Of() )

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var m1 = map[int]string{
		3: "c",
		2: "b",
		1: "a",
	}
	s := stream.OfMap(m1).
		Map(func(e types.T) types.R {
			p := e.(types.Pair)
			p.First, p.Second = p.Second, p.First
			return p
		}).
		Sorted(func(left types.T, right types.T) int {
			p1 := left.(types.Pair)
			p2 := right.(types.Pair)
			return p1.Second.(int) - p2.Second.(int)
		}).
		ToSlice()
	fmt.Println(s)
	stream.OfMap(nil).ForEach(func(e types.T) {
		fmt.Println("not print")
	})
}
Output:

[{a 1} {b 2} {c 3}]

func OfSlice added in v0.0.2

func OfSlice(slice types.T) Stream

OfSlice return a Stream. the input parameter `slice` must be a slice. if input is nil, return a empty Stream( same as Of() )

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var intArr = []int{1, 2, 3, 4}
	stream.OfSlice(intArr).ForEach(func(e types.T) {
		fmt.Printf("%d,", e)
	})
	var nilArr []int
	stream.OfSlice(nilArr).ForEach(func(e types.T) {
		fmt.Printf("should not print")
	})
	var strArr = []string{"a", "b"}
	stream.OfSlice(strArr).
		Map(func(e types.T) types.R {
			return fmt.Sprintf("<%s>", e)
		}).
		ForEach(func(e types.T) {
			fmt.Printf("%s,", e)
		})
}
Output:

1,2,3,4,<a>,<b>,

func OfStrings added in v0.0.3

func OfStrings(element ...string) Stream
Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	var ints = []string{"a", "b", "c"}
	stream.OfStrings(ints...).ForEach(func(e types.T) {
		fmt.Printf("%v(%T),", e, e)
	})
}
Output:

a(string),b(string),c(string),

func Repeat

func Repeat(e types.T) Stream

Repeat returns a infinite Stream which all element is same

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	count := stream.Repeat("a").Peek(func(t types.T) {
		fmt.Printf("%s", t)
	}).Limit(10).Count()
	fmt.Printf("\n%d\n", count)
}
Output:

aaaaaaaaaa
10

func RepeatN

func RepeatN(e types.T, count int64) Stream

RepeatN returns a Stream which has `count` element and all the element is the given `e`

Example
package main

import (
	"fmt"

	"github.com/youthlin/stream"
	"github.com/youthlin/stream/types"
)

func main() {
	stream.RepeatN(1.0, 3).ForEach(func(t types.T) {
		fmt.Printf("<%T,%v>", t, t)
	})
}
Output:

<float64,1><float64,1><float64,1>

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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