...
1 package funk
2
3 import (
4 "reflect"
5 "strings"
6 )
7
8 type JoinFnc func(lx, rx reflect.Value) reflect.Value
9
10
11 func Join(larr, rarr interface{}, fnc JoinFnc) interface{} {
12 if !IsCollection(larr) {
13 panic("First parameter must be a collection")
14 }
15 if !IsCollection(rarr) {
16 panic("Second parameter must be a collection")
17 }
18
19 lvalue := reflect.ValueOf(larr)
20 rvalue := reflect.ValueOf(rarr)
21 if NotEqual(lvalue.Type(), rvalue.Type()) {
22 panic("Parameters must have the same type")
23 }
24
25 return fnc(lvalue, rvalue).Interface()
26 }
27
28
29 func InnerJoin(lx, rx reflect.Value) reflect.Value {
30 result := reflect.MakeSlice(reflect.SliceOf(lx.Type().Elem()), 0, lx.Len()+rx.Len())
31 rhash := hashSlice(rx)
32 lhash := make(map[interface{}]struct{}, lx.Len())
33
34 for i := 0; i < lx.Len(); i++ {
35 v := lx.Index(i)
36 _, ok := rhash[v.Interface()]
37 _, alreadyExists := lhash[v.Interface()]
38 if ok && !alreadyExists {
39 lhash[v.Interface()] = struct{}{}
40 result = reflect.Append(result, v)
41 }
42 }
43 return result
44 }
45
46
47 func OuterJoin(lx, rx reflect.Value) reflect.Value {
48 ljoin := LeftJoin(lx, rx)
49 rjoin := RightJoin(lx, rx)
50
51 result := reflect.MakeSlice(reflect.SliceOf(lx.Type().Elem()), ljoin.Len()+rjoin.Len(), ljoin.Len()+rjoin.Len())
52 for i := 0; i < ljoin.Len(); i++ {
53 result.Index(i).Set(ljoin.Index(i))
54 }
55 for i := 0; i < rjoin.Len(); i++ {
56 result.Index(ljoin.Len() + i).Set(rjoin.Index(i))
57 }
58
59 return result
60 }
61
62
63 func LeftJoin(lx, rx reflect.Value) reflect.Value {
64 result := reflect.MakeSlice(reflect.SliceOf(lx.Type().Elem()), 0, lx.Len())
65 rhash := hashSlice(rx)
66
67 for i := 0; i < lx.Len(); i++ {
68 v := lx.Index(i)
69 _, ok := rhash[v.Interface()]
70 if !ok {
71 result = reflect.Append(result, v)
72 }
73 }
74 return result
75 }
76
77
78 func RightJoin(lx, rx reflect.Value) reflect.Value { return LeftJoin(rx, lx) }
79
80 func hashSlice(arr reflect.Value) map[interface{}]struct{} {
81 hash := map[interface{}]struct{}{}
82 for i := 0; i < arr.Len(); i++ {
83 v := arr.Index(i).Interface()
84 hash[v] = struct{}{}
85 }
86 return hash
87 }
88
89
90
91 func StringerJoin(elems []interface{ String() string }, sep string) string {
92 switch len(elems) {
93 case 0:
94 return ""
95 case 1:
96 return elems[0].String()
97 }
98 n := len(sep) * (len(elems) - 1)
99 for i := 0; i < len(elems); i++ {
100 n += len(elems[i].String())
101 }
102
103 var b strings.Builder
104 b.Grow(n)
105 b.WriteString(elems[0].String())
106 for _, s := range elems[1:] {
107 b.WriteString(sep)
108 b.WriteString(s.String())
109 }
110 return b.String()
111 }
112
View as plain text