Skip to content

Commit 569337c

Browse files
authored
Add methods (#2)
* stream add methods: OfSlice, OfMap * feat(stream): add methods Stream interface: ReduceBy factory methods: OfInts, OfInt64s, OfFloat32s, OfFloat64s, OfStrings * docs(readme): update readme add changelog and todo;
1 parent 1751187 commit 569337c

File tree

6 files changed

+237
-27
lines changed

6 files changed

+237
-27
lines changed

README.md

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Go Stream
2+
23
[![PkgGoDev](https://pkg.go.dev/badge/github.com/youthlin/stream)](https://pkg.go.dev/github.com/youthlin/stream)
34
[![Go Report Card](https://goreportcard.com/badge/github.com/youthlin/stream)](https://goreportcard.com/report/github.com/youthlin/stream)
45
[![Build Status](https://travis-ci.org/youthlin/stream.svg?branch=main)](https://travis-ci.org/youthlin/stream)
@@ -9,13 +10,15 @@ Go Stream, like Java 8 Stream.
910
Blog Post: https://youthlin.com/?p=1755
1011

1112
## How to get
13+
1214
```shell script
1315
go get github.com/youthlin/stream
1416
```
1517

1618
国内镜像: https://gitee.com/youthlin/stream
1719
`go.mod` 中引入模块路径 `github.com/youthlin/stream` 及版本后,
1820
再添加 replace 即可:
21+
1922
```go
2023
// go.mod
2124

@@ -26,7 +29,9 @@ replace github.com/youthlin/stream latest => gitee.com/youthlin/stream latest
2629
```
2730

2831
## Play online
29-
https://play.golang.org/p/vO8NEkdNXzY
32+
33+
https://play.golang.org/p/nPQJYqA3-Jr
34+
3035
```go
3136
package main
3237

@@ -45,16 +50,19 @@ func main() {
4550
Map(func(e types.T) types.R {
4651
return e.(int) * 2
4752
}).
48-
ReduceWith(map[int]string{}, func(m types.R, e types.T) types.R {
49-
m.(map[int]string)[e.(int)] = fmt.Sprintf("<%d>", e)
53+
ReduceWith(map[int]string{}, func(acc types.R, e types.T) types.R {
54+
m := acc.(map[int]string)
55+
m[e.(int)] = fmt.Sprintf("<%d>", e)
5056
return m
5157
})
5258
fmt.Println(m)
59+
// Output:
60+
// map[0:<0> 4:<4> 8:<8> 12:<12> 16:<16>]
5361
}
54-
5562
```
5663

5764
## Examples
65+
5866
```go
5967

6068
type Stream interface {
@@ -218,3 +226,15 @@ func TestToMap(t *testing.T) {
218226
}
219227

220228
```
229+
230+
## Change Log
231+
232+
- v0.0.3 2020-12-08 add factory method: OfInts, OfInt64s, OfFloat32s, OfFloat64s, OfStrings;
233+
add Stream method: ReduceBy
234+
- v0.0.2 2020-12-07 add factory method: OfSlice, OfMap
235+
- v0.0.1 2020-11-12 first version
236+
237+
## Todo
238+
239+
- [ ] add Benchmark test
240+
- [ ] support parallel stream

example_test.go

+74
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,47 @@ func ExampleOf() {
5555
// 1,2,3,4,
5656
}
5757

58+
func ExampleOfInts() {
59+
var ints = []int{1, 2, 3, 4}
60+
stream.OfInts(ints...).ForEach(func(e types.T) {
61+
fmt.Printf("%d,", e)
62+
})
63+
// Output:
64+
// 1,2,3,4,
65+
}
66+
func ExampleOfInt64s() {
67+
var ints = []int64{1, 2, 3, 4}
68+
stream.OfInt64s(ints...).ForEach(func(e types.T) {
69+
fmt.Printf("%d(%T),", e, e)
70+
})
71+
// Output:
72+
// 1(int64),2(int64),3(int64),4(int64),
73+
}
74+
func ExampleOfFloat32s() {
75+
var ints = []float32{1, 2, 3, 4}
76+
stream.OfFloat32s(ints...).ForEach(func(e types.T) {
77+
fmt.Printf("%v(%T),", e, e)
78+
})
79+
// Output:
80+
// 1(float32),2(float32),3(float32),4(float32),
81+
}
82+
func ExampleOfFloat64s() {
83+
var ints = []float64{1, 2, 3, 4}
84+
stream.OfFloat64s(ints...).ForEach(func(e types.T) {
85+
fmt.Printf("%v(%T),", e, e)
86+
})
87+
// Output:
88+
// 1(float64),2(float64),3(float64),4(float64),
89+
}
90+
func ExampleOfStrings() {
91+
var ints = []string{"a", "b", "c"}
92+
stream.OfStrings(ints...).ForEach(func(e types.T) {
93+
fmt.Printf("%v(%T),", e, e)
94+
})
95+
// Output:
96+
// a(string),b(string),c(string),
97+
}
98+
5899
func ExampleOfSlice() {
59100
var intArr = []int{1, 2, 3, 4}
60101
stream.OfSlice(intArr).ForEach(func(e types.T) {
@@ -386,6 +427,7 @@ func ExampleStream_AnyMatch() {
386427
// true true
387428
// false
388429
}
430+
389431
func ExampleStream_Reduce() {
390432
fmt.Println(stream.Of().Reduce(func(acc types.T, t types.T) types.T {
391433
return acc
@@ -414,6 +456,38 @@ func ExampleStream_ReduceWith() {
414456
// Output:
415457
// []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
416458
}
459+
func ExampleStream_ReduceBy() {
460+
ints := stream.IntRange(0, 10).ReduceBy(func(sizeMayNegative int64) types.R {
461+
if sizeMayNegative >= 0 {
462+
return make([]int, 0, sizeMayNegative)
463+
}
464+
fmt.Printf("IntRange: unknown size\n")
465+
return make([]int, 0)
466+
}, func(acc types.R, e types.T) types.R {
467+
result := acc.([]int)
468+
result = append(result, e.(int))
469+
return result
470+
}).([]int)
471+
fmt.Printf("%v\n", ints)
472+
int64s := stream.OfInts(ints...).ReduceBy(func(sizeMayNegative int64) types.R {
473+
if sizeMayNegative >= 0 {
474+
fmt.Printf("size=%d\n", sizeMayNegative)
475+
return make([]int64, 0, sizeMayNegative)
476+
}
477+
return make([]int64, 0)
478+
}, func(acc types.R, e types.T) types.R {
479+
result := acc.([]int64)
480+
result = append(result, int64(e.(int)))
481+
return result
482+
}).([]int64)
483+
fmt.Printf("%v\n", int64s)
484+
// Output:
485+
// IntRange: unknown size
486+
// [0 1 2 3 4 5 6 7 8 9]
487+
// size=10
488+
// [0 1 2 3 4 5 6 7 8 9]
489+
}
490+
417491
func ExampleStream_Count() {
418492
fmt.Println(stream.Of().Count())
419493
fmt.Println(stream.Of(1).Count())

factory.go

+46
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,52 @@ func Of(elements ...types.T) Stream {
5454
return newHead(it(elements...))
5555
}
5656

57+
func OfInts(element ...int) Stream {
58+
return newHead(&intsIt{
59+
base: &base{
60+
current: 0,
61+
size: len(element),
62+
},
63+
elements: element,
64+
})
65+
}
66+
func OfInt64s(element ...int64) Stream {
67+
return newHead(&int64sIt{
68+
base: &base{
69+
current: 0,
70+
size: len(element),
71+
},
72+
elements: element,
73+
})
74+
}
75+
func OfFloat32s(element ...float32) Stream {
76+
return newHead(&float32sIt{
77+
base: &base{
78+
current: 0,
79+
size: len(element),
80+
},
81+
elements: element,
82+
})
83+
}
84+
func OfFloat64s(element ...float64) Stream {
85+
return newHead(&float64sIt{
86+
base: &base{
87+
current: 0,
88+
size: len(element),
89+
},
90+
elements: element,
91+
})
92+
}
93+
func OfStrings(element ...string) Stream {
94+
return newHead(&stringIt{
95+
base: &base{
96+
current: 0,
97+
size: len(element),
98+
},
99+
elements: element,
100+
})
101+
}
102+
57103
// OfSlice return a Stream. the input parameter `slice` must be a slice.
58104
// if input is nil, return a empty Stream( same as Of() )
59105
func OfSlice(slice types.T) Stream {

impl.go

+34-22
Original file line numberDiff line numberDiff line change
@@ -234,17 +234,16 @@ func (s *stream) ForEach(consumer types.Consumer) {
234234

235235
// ToSlice 转为切片
236236
func (s *stream) ToSlice() []types.T {
237-
var slice []types.T
238-
s.terminal(newTerminalStage(func(t types.T) {
239-
slice = append(slice, t)
240-
}, begin(func(size int64) {
241-
if size > 0 {
242-
slice = make([]types.T, 0, size)
243-
} else {
244-
slice = make([]types.T, 0)
237+
return s.ReduceBy(func(count int64) types.R {
238+
if count >= 0 {
239+
return make([]types.T, 0, count)
245240
}
246-
})))
247-
return slice
241+
return make([]types.T, 0)
242+
}, func(acc types.R, t types.T) types.R {
243+
slice := acc.([]types.T)
244+
slice = append(slice, t)
245+
return slice
246+
}).([]types.T)
248247
}
249248

250249
// ToElementSlice needs a argument cause the stream may be empty
@@ -255,17 +254,17 @@ func (s *stream) ToElementSlice(some types.T) types.R {
255254
// ToRealSlice
256255
func (s *stream) ToSliceOf(typ reflect.Type) types.R {
257256
sliceType := reflect.SliceOf(typ)
258-
var sliceValue reflect.Value
259-
s.terminal(newTerminalStage(func(t types.T) {
260-
sliceValue = reflect.Append(sliceValue, reflect.ValueOf(t))
261-
}, begin(func(size int64) {
262-
if size > 0 {
263-
sliceValue = reflect.MakeSlice(sliceType, 0, int(size))
264-
} else {
265-
sliceValue = reflect.MakeSlice(sliceType, 0, 0)
257+
return s.ReduceBy(func(size int64) types.R {
258+
if size >= 0 {
259+
return reflect.MakeSlice(sliceType, 0, int(size))
266260
}
267-
})))
268-
return sliceValue.Interface()
261+
return reflect.MakeSlice(sliceType, 0, 16)
262+
}, func(acc types.R, t types.T) types.R {
263+
sliceValue := acc.(reflect.Value)
264+
sliceValue = reflect.Append(sliceValue, reflect.ValueOf(t))
265+
return sliceValue
266+
}).(reflect.Value).
267+
Interface()
269268
}
270269

271270
// AllMatch 测试是否所有元素符合断言
@@ -324,7 +323,7 @@ func (s *stream) Reduce(accumulator types.BinaryOperator) optional.Optional {
324323
return optional.Empty()
325324
}
326325

327-
// ReduceFrom 从给定的初始值 identity(类型和元素类型相同) 开始迭代 使用 accumulator(2个入参类型和返回类型相同) 累计结果
326+
// ReduceFrom 从给定的初始值 initValue(类型和元素类型相同) 开始迭代 使用 accumulator(2个入参类型和返回类型相同) 累计结果
328327
func (s *stream) ReduceFrom(initValue types.T, accumulator types.BinaryOperator) types.T {
329328
var result = initValue
330329
s.terminal(newTerminalStage(func(t types.T) {
@@ -333,7 +332,7 @@ func (s *stream) ReduceFrom(initValue types.T, accumulator types.BinaryOperator)
333332
return result
334333
}
335334

336-
// ReduceWith 使用给定的初始值 identity(类型和元素类型不同) 开始迭代 使用 accumulator( R + T -> R) 累计结果
335+
// ReduceWith 使用给定的初始值 initValue(类型和元素类型不同) 开始迭代 使用 accumulator( R + T -> R) 累计结果
337336
func (s *stream) ReduceWith(initValue types.R, accumulator func(types.R, types.T) types.R) types.R {
338337
var result = initValue
339338
s.terminal(newTerminalStage(func(t types.T) {
@@ -342,6 +341,19 @@ func (s *stream) ReduceWith(initValue types.R, accumulator func(types.R, types.T
342341
return result
343342
}
344343

344+
// ReduceBy 使用给定的初始化方法(参数是元素个数,或-1)生成 initValue, 然后使用 accumulator 累计结果
345+
// ReduceBy use `buildInitValue` to build the initValue, which parameter is a int64 means element size, or -1 if unknown size.
346+
// Then use `accumulator` to add each element to previous result
347+
func (s *stream) ReduceBy(buildInitValue func(int64) types.R, accumulator func(types.R, types.T) types.R) types.R {
348+
var result types.R
349+
s.terminal(newTerminalStage(func(e types.T) {
350+
result = accumulator(result, e)
351+
}, begin(func(count int64) {
352+
result = buildInitValue(count)
353+
})))
354+
return result
355+
}
356+
345357
func (s *stream) FindFirst() optional.Optional {
346358
var result types.T
347359
var find = false

iterator.go

+55
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,61 @@ func (s *sliceIterator) Next() types.T {
7070

7171
// endregion sliceIterator
7272

73+
type intsIt struct {
74+
*base
75+
elements []int
76+
}
77+
78+
func (i *intsIt) Next() types.T {
79+
e := i.elements[i.current]
80+
i.current++
81+
return e
82+
}
83+
84+
type int64sIt struct {
85+
*base
86+
elements []int64
87+
}
88+
89+
func (i *int64sIt) Next() types.T {
90+
e := i.elements[i.current]
91+
i.current++
92+
return e
93+
}
94+
95+
type float32sIt struct {
96+
*base
97+
elements []float32
98+
}
99+
100+
func (i *float32sIt) Next() types.T {
101+
e := i.elements[i.current]
102+
i.current++
103+
return e
104+
}
105+
106+
type float64sIt struct {
107+
*base
108+
elements []float64
109+
}
110+
111+
func (i *float64sIt) Next() types.T {
112+
e := i.elements[i.current]
113+
i.current++
114+
return e
115+
}
116+
117+
type stringIt struct {
118+
*base
119+
elements []string
120+
}
121+
122+
func (i *stringIt) Next() types.T {
123+
e := i.elements[i.current]
124+
i.current++
125+
return e
126+
}
127+
73128
// region sliceIt
74129

75130
// sliceIt 切片迭代器 反射实现

stream.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ type Stream interface {
4747
// type of initValue is same as element. (T, T) -> T
4848
ReduceFrom(initValue types.T, accumulator types.BinaryOperator) types.T
4949
// type of initValue is different from element. (R, T) -> R
50-
ReduceWith(initValue types.R, accumulator func(types.R, types.T) types.R) types.R
50+
ReduceWith(initValue types.R, accumulator func(acc types.R, e types.T) types.R) types.R
51+
// ReduceBy use `buildInitValue` to build the initValue, which parameter is a int64 means element size, or -1 if unknown size.
52+
// Then use `accumulator` to add each element to previous result
53+
ReduceBy(buildInitValue func(sizeMayNegative int64) types.R, accumulator func(acc types.R, e types.T) types.R) types.R
5154
FindFirst() optional.Optional
5255
// 返回元素个数
5356
Count() int64

0 commit comments

Comments
 (0)