-
Notifications
You must be signed in to change notification settings - Fork 61
/
partition.go
118 lines (95 loc) · 3.29 KB
/
partition.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package un
import "reflect"
func init() {
MakePartition(&Partition)
MakePartition(&PartitionInt)
// MakePartition(&PartitionString)
// MakePartition(&PartitionStringInt)
// MakePartitionP(&PartitionP)
}
// Partition func(func(A, B) bool, []A []A)
// Applies the given iterator function to partition element of a collection (slice or map).
// If the collection is a Slice, the iterator function arguments are *value, index*
// If the collection is a Map, the iterator function arguments are *value, key*
// Iterator functions accept a value, and the index or key is an optional argument.
// Note: partition does not return a value, you may want un.Map
// var Partition func(func(value, i interface{}), interface{})
var Partition func(fn interface{}, slice_or_map interface{}) ([]interface{}, []interface{})
// var Partition func(interface{}, func(interface{}) bool) ([]interface{}, []interface{})
// // PartitionP Parallel Partition
// // *Concurrently* applies the given iterator function to partition element of a collection (slice or map).
// var PartitionP func(fn interface{}, slice_or_map interface{})
// // PartitionInt
// // Applies the given iterator function to partition element of []int
// // Iterator function arguments are *value, index*
var PartitionInt func(func(value, i int), []int) ([]int, []int)
// // PartitionStringInt
// // Applies the given iterator function to partition element of map[string]int
// // Iterator function arguments are *value, key*
// var PartitionStringInt func(func(value int, key string), map[string]int)
// MakePartition implements a typed Partition function in the form Partition func(func(A, B), []A)
func MakePartition(fn interface{}) {
Maker(fn, partition)
}
type partitioner struct {
fn reflect.Value
col reflect.Value
t reflect.Value
f reflect.Value
}
func partition(values []reflect.Value) []reflect.Value {
fn, col := extractArgs(values)
kind := values[1].Kind()
p := newPartitioner(fn, col, kind)
return p.partition()
}
func newPartitioner(fn, col reflect.Value, kind reflect.Kind) *partitioner {
t, f := makePartitions(col, kind)
return &partitioner{fn: fn, col: col, t: t, f: f}
}
func (p *partitioner) partition() []reflect.Value {
switch {
case p.isSlice():
p.partitionSlice()
case p.isMap():
p.partitionMap()
}
return []reflect.Value{p.t, p.f}
}
func (p *partitioner) isSlice() bool {
return p.col.Kind() == reflect.Slice
}
func (p *partitioner) isMap() bool {
return p.col.Kind() == reflect.Map
}
func (p *partitioner) partitionSlice() {
for i := 0; i < p.col.Len(); i++ {
val := p.col.Index(i)
idx := reflect.ValueOf(i)
p.partitionate(val, idx)
}
}
func (p *partitioner) partitionMap() {
for _, key := range p.col.MapKeys() {
val := p.col.MapIndex(key)
p.partitionate(val, key)
}
}
func (p *partitioner) partitionate(val, idx_or_key reflect.Value) {
if ok := callPredicate(p.fn, val, idx_or_key); ok {
p.t = reflect.Append(p.t, val)
} else {
p.f = reflect.Append(p.f, val)
}
}
func makePartitions(col reflect.Value, kind reflect.Kind) (reflect.Value, reflect.Value) {
var t, f reflect.Value
if kind == reflect.Interface {
t = reflect.ValueOf(make([]interface{}, 0))
f = reflect.ValueOf(make([]interface{}, 0))
} else {
t = reflect.MakeSlice(col.Type(), 0, 0)
f = reflect.MakeSlice(col.Type(), 0, 0)
}
return t, f
}