Skip to content

Commit c25f30d

Browse files
author
ahl5esoft
committed
增加Chain Benchmark
IEnumerable增加Group、GroupBy 优化IEnumerable的Distinct、Enumerator、Index、Property、Select、Where
1 parent 6f2dbcf commit c25f30d

File tree

12 files changed

+161
-154
lines changed

12 files changed

+161
-154
lines changed

README.md

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -430,65 +430,46 @@ Chain2([][]int{
430430

431431
<a name="group" />
432432

433-
### Group(source, keySelector)
433+
### Group(keySelector) IEnumerable
434+
### Group(keySelector) IQuery
434435

435436
__Arguments__
436437

437-
* `source` - array or map
438438
* `keySelector` - func(element or value, index or key) anyType
439439

440-
__Return__
441-
442-
* interface{} - map[anyType][](element or value)
443-
444440
__Examples__
445441

446442
```go
447-
src := []int{ 1, 2, 3, 4, 5 }
448-
var res map[string][]int
449-
Chain(src).Group(func (n, _ int) string {
450-
if n % 2 == 0 {
451-
return "even"
452-
}
453-
return "odd"
454-
}).Value(&res)
455-
// or
456-
res := Group(src, func (n, _ int) string {
457-
if n % 2 == 0 {
443+
dst := make(map[string][]int)
444+
Chain2([]int{1, 2, 3, 4, 5}).Group(func(n, _ int) string {
445+
if n%2 == 0 {
458446
return "even"
459447
}
460448
return "odd"
461-
}).(map[string][]int)
462-
// res = map[odd:[1 3 5] even:[2 4]]
449+
}).Value(&dst)
450+
// dst = map[odd:[1 3 5] even:[2 4]]
463451
```
464452

465453
<a name="groupBy" />
466454

467-
### GroupBy(source, property)
455+
### GroupBy(fieldName) IEnumerable
456+
### GroupBy(fieldName) IQuery
468457

469458
__Arguments__
470459

471-
* `source` - array or map
472-
* `property` - property name
473-
474-
__Return__
475-
476-
* interface{} - map[property type][](element or value)
460+
* `fieldName` - field name
477461

478462
__Examples__
479463

480464
```go
481-
arr := []testModel{
465+
dst := make(map[string][]testModel)
466+
Chain2([]testModel{
482467
{ID: 1, Name: "a"},
483468
{ID: 2, Name: "a"},
484469
{ID: 3, Name: "b"},
485470
{ID: 4, Name: "b"},
486-
}
487-
var res map[string][]testModel
488-
Chain(arr).GroupBy("name").Value(&res)
489-
// or
490-
res := GroupBy(arr, "name").(map[string][]testModel)
491-
// res = map[a:[{{0} 1 a} {{0} 2 a}] b:[{{0} 3 b} {{0} 4 b}]]
471+
}).GroupBy("Name").Value(&dst)
472+
// dst = map[a:[{1 a} {2 a}] b:[{3 b} {4 b}]]
492473
```
493474

494475
<a name="index" />
@@ -1218,6 +1199,13 @@ __Same__
12181199
* `FilterBy`
12191200

12201201
## Release Notes
1202+
~~~
1203+
v1.5.0 (2019-06-18)
1204+
* 增加Chain Benchmark
1205+
* IEnumerable增加Group、GroupBy
1206+
* 优化IEnumerable的Distinct、Enumerator、Index、Property、Select、Where
1207+
~~~
1208+
12211209
~~~
12221210
v1.4.0 (2019-06-15)
12231211
* Reduce、Take支持IEnumerable

chain_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package underscore
22

3+
import "testing"
4+
35
var (
46
benchmarkSize = 1000000
57
)
@@ -14,3 +16,25 @@ type testNestedModel struct {
1416

1517
Age int
1618
}
19+
20+
func Benchmark_Chain(b *testing.B) {
21+
for n := 0; n < b.N; n++ {
22+
var dst int
23+
Range(1, benchmarkSize, 1).Map(func(r, _ int) int {
24+
return -r
25+
}).Where(func(r, _ int) bool {
26+
return r < -20
27+
}).First().Value(&dst)
28+
}
29+
}
30+
31+
func Benchmark_Chain_New(b *testing.B) {
32+
for n := 0; n < b.N; n++ {
33+
var dst int
34+
Range2(1, benchmarkSize, 1).Select(func(r, _ int) int {
35+
return -r
36+
}).Where(func(r, _ int) bool {
37+
return r < -20
38+
}).First().Value(&dst)
39+
}
40+
}

distinct.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ func (m enumerable) Distinct(selector interface{}) IEnumerable {
2121
for ok = iterator.MoveNext(); ok; ok = iterator.MoveNext() {
2222
valueRV = iterator.GetValue()
2323
keyRV = iterator.GetKey()
24-
v := getRV(
25-
selectorRV.Call([]reflect.Value{valueRV, keyRV})[0],
26-
).Interface()
24+
v := getFuncReturnRV(selectorRV, iterator).Interface()
2725
if _, has := set[v]; !has {
2826
set[v] = true
2927
return

enumerator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func (m enumerator) GetKey() reflect.Value {
1616
}
1717

1818
func (m enumerator) GetValue() reflect.Value {
19-
return getRV(m.value)
19+
return getRealRV(m.value)
2020
}
2121

2222
func (m *enumerator) MoveNext() (ok bool) {

group.go

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package underscore
22

3-
import (
4-
"reflect"
5-
)
3+
import "reflect"
64

7-
// Group is 分组
8-
func Group(source, keySelector interface{}) interface{} {
5+
func (m *query) Group(keySelector interface{}) IQuery {
96
var groupRV reflect.Value
10-
each(source, keySelector, func(groupKeyRV, valueRV, _ reflect.Value) bool {
7+
each(m.Source, keySelector, func(groupKeyRV, valueRV, _ reflect.Value) bool {
118
groupValueRT := reflect.SliceOf(valueRV.Type())
129
if !groupRV.IsValid() {
1310
groupRT := reflect.MapOf(groupKeyRV.Type(), groupValueRT)
@@ -24,27 +21,67 @@ func Group(source, keySelector interface{}) interface{} {
2421
return false
2522
})
2623
if groupRV.IsValid() {
27-
return groupRV.Interface()
24+
m.Source = groupRV.Interface()
2825
}
29-
return nil
26+
27+
return m
3028
}
3129

32-
// GroupBy is 根据某个属性分组
33-
func GroupBy(source interface{}, property string) interface{} {
30+
func (m *query) GroupBy(property string) IQuery {
3431
getPropertyRV := PropertyRV(property)
35-
return Group(source, func(value, _ interface{}) facade {
32+
return m.Group(func(value, _ interface{}) facade {
3633
return facade{
3734
getPropertyRV(value),
3835
}
3936
})
4037
}
4138

42-
func (m *query) Group(keySelector interface{}) IQuery {
43-
m.Source = Group(m.Source, keySelector)
44-
return m
39+
func (m enumerable) Group(keySelector interface{}) enumerable {
40+
return enumerable{
41+
Enumerator: func() IEnumerator {
42+
groupRVs := make(map[interface{}]reflect.Value)
43+
iterator := m.GetEnumerator()
44+
keySelectorRV := reflect.ValueOf(keySelector)
45+
keyRVs := make([]reflect.Value, 0)
46+
for ok := iterator.MoveNext(); ok; ok = iterator.MoveNext() {
47+
keyRV := getFuncReturnRV(keySelectorRV, iterator)
48+
key := keyRV.Interface()
49+
groupRV, ok := groupRVs[key]
50+
if !ok {
51+
groupRV = reflect.MakeSlice(
52+
reflect.SliceOf(
53+
iterator.GetValue().Type(),
54+
),
55+
0,
56+
0,
57+
)
58+
keyRVs = append(keyRVs, keyRV)
59+
}
60+
groupRVs[key] = reflect.Append(
61+
groupRV,
62+
iterator.GetValue(),
63+
)
64+
}
65+
index := 0
66+
return &enumerator{
67+
MoveNextFunc: func() (valueRV reflect.Value, keyRV reflect.Value, ok bool) {
68+
if ok = index < len(keyRVs); ok {
69+
keyRV = keyRVs[index]
70+
valueRV = groupRVs[keyRV.Interface()]
71+
index++
72+
}
73+
return
74+
},
75+
}
76+
},
77+
}
4578
}
4679

47-
func (m *query) GroupBy(property string) IQuery {
48-
m.Source = GroupBy(m.Source, property)
49-
return m
80+
func (m enumerable) GroupBy(fieldName string) enumerable {
81+
getter := PropertyRV(fieldName)
82+
return m.Group(func(value, _ interface{}) facade {
83+
return facade{
84+
getter(value),
85+
}
86+
})
5087
}

group_test.go

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,53 @@
11
package underscore
22

3-
import (
4-
"testing"
5-
)
3+
import "testing"
64

7-
func Test_Group(t *testing.T) {
8-
dic := Group([]int{1, 2, 3, 4, 5}, func(n, _ int) string {
9-
if n%2 == 0 {
10-
return "even"
11-
}
12-
return "odd"
13-
}).(map[string][]int)
14-
if len(dic["even"]) != 2 {
15-
t.Error("wrong")
5+
func Benchmark_Group(b *testing.B) {
6+
for n := 0; n < b.N; n++ {
7+
dst := make([]int, 0)
8+
Range(1, benchmarkSize, 1).Group(func(n, _ int) string {
9+
if n%2 == 0 {
10+
return "even"
11+
}
12+
return "odd"
13+
}).Value(&dst)
1614
}
1715
}
1816

19-
func Test_GroupBy(t *testing.T) {
20-
arr := []testModel{
21-
{ID: 1, Name: "a"},
22-
{ID: 2, Name: "a"},
23-
{ID: 3, Name: "b"},
24-
{ID: 4, Name: "b"},
25-
}
26-
dic := GroupBy(arr, "name").(map[string][]testModel)
27-
if len(dic) != 2 {
28-
t.Error("wrong")
17+
func Benchmark_Group_New(b *testing.B) {
18+
for n := 0; n < b.N; n++ {
19+
dst := make([]int, 0)
20+
Range2(1, benchmarkSize, 1).Group(func(n, _ int) string {
21+
if n%2 == 0 {
22+
return "even"
23+
}
24+
return "odd"
25+
}).Value(&dst)
2926
}
3027
}
3128

32-
func Test_Chain_Group(t *testing.T) {
33-
res := make(map[string][]int)
34-
Chain([]int{1, 2, 3, 4, 5}).Group(func(n, _ int) string {
29+
func Test_Group(t *testing.T) {
30+
dst := make(map[string][]int)
31+
Chain2([]int{1, 2, 3, 4, 5}).Group(func(n, _ int) string {
3532
if n%2 == 0 {
3633
return "even"
3734
}
3835
return "odd"
39-
}).Value(&res)
40-
if len(res["even"]) != 2 {
36+
}).Value(&dst)
37+
if len(dst["even"]) != 2 {
4138
t.Error("wrong")
4239
}
4340
}
4441

45-
func Test_Chain_GroupBy(t *testing.T) {
46-
res := make(map[string][]testModel)
47-
Chain([]testModel{
42+
func Test_GroupBy(t *testing.T) {
43+
dst := make(map[string][]testModel)
44+
Chain2([]testModel{
4845
{ID: 1, Name: "a"},
4946
{ID: 2, Name: "a"},
5047
{ID: 3, Name: "b"},
5148
{ID: 4, Name: "b"},
52-
}).GroupBy("Name").Value(&res)
53-
if len(res) != 2 {
49+
}).GroupBy("Name").Value(&dst)
50+
if len(dst) != 2 {
5451
t.Error("wrong")
5552
}
5653
}

i-enumerable.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ type IEnumerable interface {
1818
FindIndexBy(dict map[string]interface{}) int
1919
First() IEnumerable
2020
GetEnumerator() IEnumerator
21+
Group(keySelector interface{}) enumerable
22+
GroupBy(fieldName string) enumerable
2123
Index(keySelector interface{}) IEnumerable
2224
IndexBy(fieldName string) IEnumerable
2325
Keys() IEnumerable

index.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,7 @@ func (m enumerable) Index(keySelector interface{}) IEnumerable {
5050
return &enumerator{
5151
MoveNextFunc: func() (valueRV reflect.Value, keyRV reflect.Value, ok bool) {
5252
if ok = iterator.MoveNext(); ok {
53-
keyRV = getRV(
54-
keySelectorRV.Call([]reflect.Value{
55-
iterator.GetValue(),
56-
iterator.GetKey(),
57-
})[0],
58-
)
53+
keyRV = getFuncReturnRV(keySelectorRV, iterator)
5954
valueRV = iterator.GetValue()
6055
}
6156

property.go

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func Property(name string) func(interface{}) interface{} {
2020
func PropertyRV(name string) GetProeprtyRVFunc {
2121
var getter GetProeprtyRVFunc
2222
getter = func(item interface{}) reflect.Value {
23-
itemRV := getRV(item)
23+
itemRV := getRealRV(item)
2424
itemRT := itemRV.Type()
2525
for i := 0; i < itemRT.NumField(); i++ {
2626
field := itemRT.Field(i)
@@ -42,20 +42,3 @@ func PropertyRV(name string) GetProeprtyRVFunc {
4242
}
4343
return getter
4444
}
45-
46-
func getRV(v interface{}) reflect.Value {
47-
rv := reflect.ValueOf(v)
48-
if rv.Type() == rtOfRV {
49-
rv = v.(reflect.Value)
50-
}
51-
52-
if rv.Kind() == reflect.Ptr {
53-
rv = rv.Elem()
54-
}
55-
56-
if rv.Type() == facadeRT {
57-
rv = rv.Interface().(facade).Real
58-
}
59-
60-
return rv
61-
}

0 commit comments

Comments
 (0)