CrossJoinX + CrossJoinByX

This commit is contained in:
Samuel Berthe
2025-01-25 00:19:26 +01:00
parent c4ae516f73
commit 2876510f3c
6 changed files with 758 additions and 69 deletions

View File

@@ -122,7 +122,6 @@ Supported helpers for slices:
- [IsSorted](#issorted)
- [IsSortedByKey](#issortedbykey)
- [Splice](#Splice)
- [CrossJoin](#CrossJoin)
Supported helpers for maps:
@@ -178,6 +177,8 @@ Supported helpers for tuples:
- [ZipBy2 -> ZipBy9](#zipby2---zipby9)
- [Unzip2 -> Unzip9](#unzip2---unzip9)
- [UnzipBy2 -> UnzipBy9](#unzipby2---unzipby9)
- [CrossJoin2 -> CrossJoin2](#crossjoin2---crossjoin9)
- [CrossJoinBy2 -> CrossJoinBy2](#crossjoinby2---crossjoinby9)
Supported helpers for time and duration:
@@ -1064,19 +1065,6 @@ result = lo.Splice([]string{"a", "b"}, 42, "1", "2")
[[play](https://go.dev/play/p/wiG6XyBBu49)]
### CrossJoin
CrossJoin calculates the cartesian product of two lists. It returns a list of tuples where the first element includes the elements of the first parameter, and the second element contains the elements of the second parameter.
It returns an empty list if either, or both parameters are empty
```go
result := lo.CrossJoin([]string{"a", "b", "c"}, []int{1, 2, 3})
// [][2]interface{}{{"a", 1}, {"a", 2}, {"a", 3}, {"b", 1}, {"b", 2}, {"b", 3}, {"c", 1}, {"c", 2}, {"c", 3}
```
[[play](https://go.dev/play/p/2-DOGciKvAB)]
### Keys
Creates a slice of the map keys.
@@ -1710,6 +1698,36 @@ a, b := lo.UnzipBy2([]string{"hello", "john", "doe"}, func(str string) (string,
// []int{5, 4, 3}
```
### CrossJoin2 -> CrossJoin9
Combines every items from one list with every items from others. It is the cartesian product of lists received as arguments. It returns an empty list if a list is empty.
```go
result := lo.CrossJoin2([]string{"hello", "john", "doe"}, []int{1, 2})
// lo.Tuple2{"hello", 1}
// lo.Tuple2{"hello", 2}
// lo.Tuple2{"john", 1}
// lo.Tuple2{"john", 2}
// lo.Tuple2{"doe", 1}
// lo.Tuple2{"doe", 2}
```
### CrossJoinBy2 -> CrossJoinBy9
Combines every items from one list with every items from others. It is the cartesian product of lists received as arguments. The project function is used to create the output values. It returns an empty list if a list is empty.
```go
result := lo.CrossJoinBy2([]string{"hello", "john", "doe"}, []int{1, 2}, func(a A, b B) string {
return fmt.Sprintf("%s - %d", a, b)
})
// "hello - 1"
// "hello - 2"
// "john - 1"
// "john - 2"
// "doe - 1"
// "doe - 2"
```
### Duration
Returns the time taken to execute a function.

View File

@@ -708,27 +708,3 @@ func Splice[T any, Slice ~[]T](collection Slice, i int, elements ...T) Slice {
return append(append(append(output, collection[:i]...), elements...), collection[i:]...)
}
// CrossJoin calculates the cartesian product of two lists. It returns a list of
// tuples where the first element includes the elements of the first parameter, and
// the second element contains the elements of the second parameter.
// It returns an empty list if either, or both parameters are empty
// Play: https://go.dev/play/p/2-DOGciKvAB
func CrossJoin[T, U any](listOne []T, listTwo []U) [][2]interface{} {
if len(listOne) == 0 || len(listTwo) == 0 {
return make([][2]interface{}, 0)
}
cartesianProduct := make([][2]interface{}, 0, len(listOne)*len(listTwo))
for _, a := range listOne {
for _, b := range listTwo {
cartesianProduct = append(cartesianProduct, [2]interface{}{a, b})
}
}
return cartesianProduct
}

View File

@@ -1046,34 +1046,3 @@ func TestSplice(t *testing.T) {
nonempty := Splice(allStrings, 1, "1", "2")
is.IsType(nonempty, allStrings, "type preserved")
}
func TestCrossJoin(t *testing.T) {
t.Parallel()
is := assert.New(t)
listOne := []string{"a", "b", "c"}
listTwo := []int{1, 2, 3}
emptyList := make([][2]any, 0)
mixedList := []any{9.6, 4, "foobar"}
results := CrossJoin(emptyList, listTwo)
is.Equal(emptyList, results)
results = CrossJoin(listOne, emptyList)
is.Equal(emptyList, results)
results = CrossJoin(emptyList, emptyList)
is.Equal(emptyList, results)
results = CrossJoin([]string{"a"}, listTwo)
is.Equal([][2]any{{"a", 1}, {"a", 2}, {"a", 3}}, results)
results = CrossJoin(listOne, []int{1})
is.Equal([][2]any{{"a", 1}, {"b", 1}, {"c", 1}}, results)
results = CrossJoin(listOne, listTwo)
is.Equal([][2]any{{"a", 1}, {"a", 2}, {"a", 3}, {"b", 1}, {"b", 2}, {"b", 3}, {"c", 1}, {"c", 2}, {"c", 3}}, results)
results = CrossJoin(listOne, mixedList)
is.Equal([][2]any{{"a", 9.6}, {"a", 4}, {"a", "foobar"}, {"b", 9.6}, {"b", 4}, {"b", "foobar"}, {"c", 9.6}, {"c", 4}, {"c", "foobar"}}, results)
}

280
tuples.go
View File

@@ -867,3 +867,283 @@ func UnzipBy9[In any, A any, B any, C any, D any, E any, F any, G any, H any, I
return r1, r2, r3, r4, r5, r6, r7, r8, r9
}
// CrossJoin2 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin2[A, B any](listA []A, listB []B) []Tuple2[A, B] {
return CrossJoinBy2(listA, listB, T2[A, B])
}
// CrossJoin3 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin3[A, B, C any](listA []A, listB []B, listC []C) []Tuple3[A, B, C] {
return CrossJoinBy3(listA, listB, listC, T3[A, B, C])
}
// CrossJoin4 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin4[A, B, C, D any](listA []A, listB []B, listC []C, listD []D) []Tuple4[A, B, C, D] {
return CrossJoinBy4(listA, listB, listC, listD, T4[A, B, C, D])
}
// CrossJoin5 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin5[A, B, C, D, E any](listA []A, listB []B, listC []C, listD []D, listE []E) []Tuple5[A, B, C, D, E] {
return CrossJoinBy5(listA, listB, listC, listD, listE, T5[A, B, C, D, E])
}
// CrossJoin6 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin6[A, B, C, D, E, F any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F) []Tuple6[A, B, C, D, E, F] {
return CrossJoinBy6(listA, listB, listC, listD, listE, listF, T6[A, B, C, D, E, F])
}
// CrossJoin7 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin7[A, B, C, D, E, F, G any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G) []Tuple7[A, B, C, D, E, F, G] {
return CrossJoinBy7(listA, listB, listC, listD, listE, listF, listG, T7[A, B, C, D, E, F, G])
}
// CrossJoin8 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin8[A, B, C, D, E, F, G, H any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H) []Tuple8[A, B, C, D, E, F, G, H] {
return CrossJoinBy8(listA, listB, listC, listD, listE, listF, listG, listH, T8[A, B, C, D, E, F, G, H])
}
// CrossJoin9 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty.
func CrossJoin9[A, B, C, D, E, F, G, H, I any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, listI []I) []Tuple9[A, B, C, D, E, F, G, H, I] {
return CrossJoinBy9(listA, listB, listC, listD, listE, listF, listG, listH, listI, T9[A, B, C, D, E, F, G, H, I])
}
// CrossJoinBy2 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy2[A, B, Out any](listA []A, listB []B, project func(a A, b B) Out) []Out {
size := len(listA) * len(listB)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
result = append(result, project(a, b))
}
}
return result
}
// CrossJoinBy3 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy3[A, B, C, Out any](listA []A, listB []B, listC []C, project func(a A, b B, c C) Out) []Out {
size := len(listA) * len(listB) * len(listC)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
result = append(result, project(a, b, c))
}
}
}
return result
}
// CrossJoinBy4 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy4[A, B, C, D, Out any](listA []A, listB []B, listC []C, listD []D, project func(a A, b B, c C, d D) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
for _, d := range listD {
result = append(result, project(a, b, c, d))
}
}
}
}
return result
}
// CrossJoinBy5 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy5[A, B, C, D, E, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, project func(a A, b B, c C, d D, e E) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
for _, d := range listD {
for _, e := range listE {
result = append(result, project(a, b, c, d, e))
}
}
}
}
}
return result
}
// CrossJoinBy6 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy6[A, B, C, D, E, F, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, project func(a A, b B, c C, d D, e E, f F) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
for _, d := range listD {
for _, e := range listE {
for _, f := range listF {
result = append(result, project(a, b, c, d, e, f))
}
}
}
}
}
}
return result
}
// CrossJoinBy7 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy7[A, B, C, D, E, F, G, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, project func(a A, b B, c C, d D, e E, f F, g G) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
for _, d := range listD {
for _, e := range listE {
for _, f := range listF {
for _, g := range listG {
result = append(result, project(a, b, c, d, e, f, g))
}
}
}
}
}
}
}
return result
}
// CrossJoinBy8 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy8[A, B, C, D, E, F, G, H, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, project func(a A, b B, c C, d D, e E, f F, g G, h H) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
for _, d := range listD {
for _, e := range listE {
for _, f := range listF {
for _, g := range listG {
for _, h := range listH {
result = append(result, project(a, b, c, d, e, f, g, h))
}
}
}
}
}
}
}
}
return result
}
// CrossJoinBy9 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. The project function
// is used to create the output values.
// It returns an empty list if a list is empty.
func CrossJoinBy9[A, B, C, D, E, F, G, H, I, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, listI []I, project func(a A, b B, c C, d D, e E, f F, g G, h H, i I) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH) * len(listI)
if size == 0 {
return []Out{}
}
result := make([]Out, 0, size)
for _, a := range listA {
for _, b := range listB {
for _, c := range listC {
for _, d := range listD {
for _, e := range listE {
for _, f := range listF {
for _, g := range listG {
for _, h := range listH {
for _, i := range listI {
result = append(result, project(a, b, c, d, e, f, g, h, i))
}
}
}
}
}
}
}
}
}
return result
}

View File

@@ -195,3 +195,387 @@ func ExampleUnzip9() {
fmt.Printf("%v %v %v %v %v %v %v %v %v", a, b, c, d, e, f, g, h, i)
// Output: [hello] [2] [true] [{bar}] [4.2] [plop] [false] [42] [hello world]
}
func ExampleCrossJoin2() {
result := CrossJoin2([]string{"a", "b"}, []int{1, 2, 3, 4})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1}
// {a 2}
// {a 3}
// {a 4}
// {b 1}
// {b 2}
// {b 3}
// {b 4}
}
func ExampleCrossJoin3() {
result := CrossJoin3([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true}
// {a 1 false}
// {a 2 true}
// {a 2 false}
// {a 3 true}
// {a 3 false}
// {a 4 true}
// {a 4 false}
// {b 1 true}
// {b 1 false}
// {b 2 true}
// {b 2 false}
// {b 3 true}
// {b 3 false}
// {b 4 true}
// {b 4 false}
}
func ExampleCrossJoin4() {
result := CrossJoin4([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true {bar}}
// {a 1 false {bar}}
// {a 2 true {bar}}
// {a 2 false {bar}}
// {a 3 true {bar}}
// {a 3 false {bar}}
// {a 4 true {bar}}
// {a 4 false {bar}}
// {b 1 true {bar}}
// {b 1 false {bar}}
// {b 2 true {bar}}
// {b 2 false {bar}}
// {b 3 true {bar}}
// {b 3 false {bar}}
// {b 4 true {bar}}
// {b 4 false {bar}}
}
func ExampleCrossJoin5() {
result := CrossJoin5([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true {bar} 4.2}
// {a 1 false {bar} 4.2}
// {a 2 true {bar} 4.2}
// {a 2 false {bar} 4.2}
// {a 3 true {bar} 4.2}
// {a 3 false {bar} 4.2}
// {a 4 true {bar} 4.2}
// {a 4 false {bar} 4.2}
// {b 1 true {bar} 4.2}
// {b 1 false {bar} 4.2}
// {b 2 true {bar} 4.2}
// {b 2 false {bar} 4.2}
// {b 3 true {bar} 4.2}
// {b 3 false {bar} 4.2}
// {b 4 true {bar} 4.2}
// {b 4 false {bar} 4.2}
}
func ExampleCrossJoin6() {
result := CrossJoin6([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true {bar} 4.2 plop}
// {a 1 false {bar} 4.2 plop}
// {a 2 true {bar} 4.2 plop}
// {a 2 false {bar} 4.2 plop}
// {a 3 true {bar} 4.2 plop}
// {a 3 false {bar} 4.2 plop}
// {a 4 true {bar} 4.2 plop}
// {a 4 false {bar} 4.2 plop}
// {b 1 true {bar} 4.2 plop}
// {b 1 false {bar} 4.2 plop}
// {b 2 true {bar} 4.2 plop}
// {b 2 false {bar} 4.2 plop}
// {b 3 true {bar} 4.2 plop}
// {b 3 false {bar} 4.2 plop}
// {b 4 true {bar} 4.2 plop}
// {b 4 false {bar} 4.2 plop}
}
func ExampleCrossJoin7() {
result := CrossJoin7([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, []bool{false})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true {bar} 4.2 plop false}
// {a 1 false {bar} 4.2 plop false}
// {a 2 true {bar} 4.2 plop false}
// {a 2 false {bar} 4.2 plop false}
// {a 3 true {bar} 4.2 plop false}
// {a 3 false {bar} 4.2 plop false}
// {a 4 true {bar} 4.2 plop false}
// {a 4 false {bar} 4.2 plop false}
// {b 1 true {bar} 4.2 plop false}
// {b 1 false {bar} 4.2 plop false}
// {b 2 true {bar} 4.2 plop false}
// {b 2 false {bar} 4.2 plop false}
// {b 3 true {bar} 4.2 plop false}
// {b 3 false {bar} 4.2 plop false}
// {b 4 true {bar} 4.2 plop false}
// {b 4 false {bar} 4.2 plop false}
}
func ExampleCrossJoin8() {
result := CrossJoin8([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, []bool{false}, []int{42})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true {bar} 4.2 plop false 42}
// {a 1 false {bar} 4.2 plop false 42}
// {a 2 true {bar} 4.2 plop false 42}
// {a 2 false {bar} 4.2 plop false 42}
// {a 3 true {bar} 4.2 plop false 42}
// {a 3 false {bar} 4.2 plop false 42}
// {a 4 true {bar} 4.2 plop false 42}
// {a 4 false {bar} 4.2 plop false 42}
// {b 1 true {bar} 4.2 plop false 42}
// {b 1 false {bar} 4.2 plop false 42}
// {b 2 true {bar} 4.2 plop false 42}
// {b 2 false {bar} 4.2 plop false 42}
// {b 3 true {bar} 4.2 plop false 42}
// {b 3 false {bar} 4.2 plop false 42}
// {b 4 true {bar} 4.2 plop false 42}
// {b 4 false {bar} 4.2 plop false 42}
}
func ExampleCrossJoin9() {
result := CrossJoin9([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, []bool{false}, []int{42}, []string{"hello world"})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// {a 1 true {bar} 4.2 plop false 42 hello world}
// {a 1 false {bar} 4.2 plop false 42 hello world}
// {a 2 true {bar} 4.2 plop false 42 hello world}
// {a 2 false {bar} 4.2 plop false 42 hello world}
// {a 3 true {bar} 4.2 plop false 42 hello world}
// {a 3 false {bar} 4.2 plop false 42 hello world}
// {a 4 true {bar} 4.2 plop false 42 hello world}
// {a 4 false {bar} 4.2 plop false 42 hello world}
// {b 1 true {bar} 4.2 plop false 42 hello world}
// {b 1 false {bar} 4.2 plop false 42 hello world}
// {b 2 true {bar} 4.2 plop false 42 hello world}
// {b 2 false {bar} 4.2 plop false 42 hello world}
// {b 3 true {bar} 4.2 plop false 42 hello world}
// {b 3 false {bar} 4.2 plop false 42 hello world}
// {b 4 true {bar} 4.2 plop false 42 hello world}
// {b 4 false {bar} 4.2 plop false 42 hello world}
}
func ExampleCrossJoinBy2() {
result := CrossJoinBy2([]string{"a", "b"}, []int{1, 2, 3, 4}, func(a string, b int) string {
return fmt.Sprintf("%v-%v", a, b)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1
// a-2
// a-3
// a-4
// b-1
// b-2
// b-3
// b-4
}
func ExampleCrossJoinBy3() {
result := CrossJoinBy3([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, func(a string, b int, c bool) string {
return fmt.Sprintf("%v-%v-%v", a, b, c)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true
// a-1-false
// a-2-true
// a-2-false
// a-3-true
// a-3-false
// a-4-true
// a-4-false
// b-1-true
// b-1-false
// b-2-true
// b-2-false
// b-3-true
// b-3-false
// b-4-true
// b-4-false
}
func ExampleCrossJoinBy4() {
result := CrossJoinBy4([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, func(a string, b int, c bool, d foo) string {
return fmt.Sprintf("%v-%v-%v-%v", a, b, c, d)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true-{bar}
// a-1-false-{bar}
// a-2-true-{bar}
// a-2-false-{bar}
// a-3-true-{bar}
// a-3-false-{bar}
// a-4-true-{bar}
// a-4-false-{bar}
// b-1-true-{bar}
// b-1-false-{bar}
// b-2-true-{bar}
// b-2-false-{bar}
// b-3-true-{bar}
// b-3-false-{bar}
// b-4-true-{bar}
// b-4-false-{bar}
}
func ExampleCrossJoinBy5() {
result := CrossJoinBy5([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, func(a string, b int, c bool, d foo, e float64) string {
return fmt.Sprintf("%v-%v-%v-%v-%v", a, b, c, d, e)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true-{bar}-4.2
// a-1-false-{bar}-4.2
// a-2-true-{bar}-4.2
// a-2-false-{bar}-4.2
// a-3-true-{bar}-4.2
// a-3-false-{bar}-4.2
// a-4-true-{bar}-4.2
// a-4-false-{bar}-4.2
// b-1-true-{bar}-4.2
// b-1-false-{bar}-4.2
// b-2-true-{bar}-4.2
// b-2-false-{bar}-4.2
// b-3-true-{bar}-4.2
// b-3-false-{bar}-4.2
// b-4-true-{bar}-4.2
// b-4-false-{bar}-4.2
}
func ExampleCrossJoinBy6() {
result := CrossJoinBy6([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, func(a string, b int, c bool, d foo, e float64, f string) string {
return fmt.Sprintf("%v-%v-%v-%v-%v-%v", a, b, c, d, e, f)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true-{bar}-4.2-plop
// a-1-false-{bar}-4.2-plop
// a-2-true-{bar}-4.2-plop
// a-2-false-{bar}-4.2-plop
// a-3-true-{bar}-4.2-plop
// a-3-false-{bar}-4.2-plop
// a-4-true-{bar}-4.2-plop
// a-4-false-{bar}-4.2-plop
// b-1-true-{bar}-4.2-plop
// b-1-false-{bar}-4.2-plop
// b-2-true-{bar}-4.2-plop
// b-2-false-{bar}-4.2-plop
// b-3-true-{bar}-4.2-plop
// b-3-false-{bar}-4.2-plop
// b-4-true-{bar}-4.2-plop
// b-4-false-{bar}-4.2-plop
}
func ExampleCrossJoinBy7() {
result := CrossJoinBy7([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, []bool{false}, func(a string, b int, c bool, d foo, e float64, f string, g bool) string {
return fmt.Sprintf("%v-%v-%v-%v-%v-%v-%v", a, b, c, d, e, f, g)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true-{bar}-4.2-plop-false
// a-1-false-{bar}-4.2-plop-false
// a-2-true-{bar}-4.2-plop-false
// a-2-false-{bar}-4.2-plop-false
// a-3-true-{bar}-4.2-plop-false
// a-3-false-{bar}-4.2-plop-false
// a-4-true-{bar}-4.2-plop-false
// a-4-false-{bar}-4.2-plop-false
// b-1-true-{bar}-4.2-plop-false
// b-1-false-{bar}-4.2-plop-false
// b-2-true-{bar}-4.2-plop-false
// b-2-false-{bar}-4.2-plop-false
// b-3-true-{bar}-4.2-plop-false
// b-3-false-{bar}-4.2-plop-false
// b-4-true-{bar}-4.2-plop-false
// b-4-false-{bar}-4.2-plop-false
}
func ExampleCrossJoinBy8() {
result := CrossJoinBy8([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, []bool{false}, []int{42}, func(a string, b int, c bool, d foo, e float64, f string, g bool, h int) string {
return fmt.Sprintf("%v-%v-%v-%v-%v-%v-%v-%v", a, b, c, d, e, f, g, h)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true-{bar}-4.2-plop-false-42
// a-1-false-{bar}-4.2-plop-false-42
// a-2-true-{bar}-4.2-plop-false-42
// a-2-false-{bar}-4.2-plop-false-42
// a-3-true-{bar}-4.2-plop-false-42
// a-3-false-{bar}-4.2-plop-false-42
// a-4-true-{bar}-4.2-plop-false-42
// a-4-false-{bar}-4.2-plop-false-42
// b-1-true-{bar}-4.2-plop-false-42
// b-1-false-{bar}-4.2-plop-false-42
// b-2-true-{bar}-4.2-plop-false-42
// b-2-false-{bar}-4.2-plop-false-42
// b-3-true-{bar}-4.2-plop-false-42
// b-3-false-{bar}-4.2-plop-false-42
// b-4-true-{bar}-4.2-plop-false-42
// b-4-false-{bar}-4.2-plop-false-42
}
func ExampleCrossJoinBy9() {
result := CrossJoinBy9([]string{"a", "b"}, []int{1, 2, 3, 4}, []bool{true, false}, []foo{{bar: "bar"}}, []float64{4.2}, []string{"plop"}, []bool{false}, []int{42}, []string{"hello world"}, func(a string, b int, c bool, d foo, e float64, f string, g bool, h int, i string) string {
return fmt.Sprintf("%v-%v-%v-%v-%v-%v-%v-%v-%v", a, b, c, d, e, f, g, h, i)
})
for _, r := range result {
fmt.Printf("%v\n", r)
}
// Output:
// a-1-true-{bar}-4.2-plop-false-42-hello world
// a-1-false-{bar}-4.2-plop-false-42-hello world
// a-2-true-{bar}-4.2-plop-false-42-hello world
// a-2-false-{bar}-4.2-plop-false-42-hello world
// a-3-true-{bar}-4.2-plop-false-42-hello world
// a-3-false-{bar}-4.2-plop-false-42-hello world
// a-4-true-{bar}-4.2-plop-false-42-hello world
// a-4-false-{bar}-4.2-plop-false-42-hello world
// b-1-true-{bar}-4.2-plop-false-42-hello world
// b-1-false-{bar}-4.2-plop-false-42-hello world
// b-2-true-{bar}-4.2-plop-false-42-hello world
// b-2-false-{bar}-4.2-plop-false-42-hello world
// b-3-true-{bar}-4.2-plop-false-42-hello world
// b-3-false-{bar}-4.2-plop-false-42-hello world
// b-4-true-{bar}-4.2-plop-false-42-hello world
// b-4-false-{bar}-4.2-plop-false-42-hello world
}

View File

@@ -529,3 +529,65 @@ func TestUnzipBy(t *testing.T) {
is.Equal(r1, []string{"aa", "bb"})
is.Equal(r2, []int{2, 4})
}
func TestCrossJoin(t *testing.T) {
t.Parallel()
is := assert.New(t)
listOne := []string{"a", "b", "c"}
listTwo := []int{1, 2, 3}
emptyList := []any{}
mixedList := []any{9.6, 4, "foobar"}
results1 := CrossJoin2(emptyList, listTwo)
is.Len(results1, 0)
results2 := CrossJoin2(listOne, emptyList)
is.Len(results2, 0)
results3 := CrossJoin2(emptyList, emptyList)
is.Len(results3, 0)
results4 := CrossJoin2([]string{"a"}, listTwo)
is.Equal([]Tuple2[string, int]{T2("a", 1), T2("a", 2), T2("a", 3)}, results4)
results5 := CrossJoin2(listOne, []int{1})
is.Equal([]Tuple2[string, int]{T2("a", 1), T2("b", 1), T2("c", 1)}, results5)
results6 := CrossJoin2(listOne, listTwo)
is.Equal([]Tuple2[string, int]{T2("a", 1), T2("a", 2), T2("a", 3), T2("b", 1), T2("b", 2), T2("b", 3), T2("c", 1), T2("c", 2), T2("c", 3)}, results6)
results7 := CrossJoin2(listOne, mixedList)
is.Equal([]Tuple2[string, any]{T2[string, any]("a", 9.6), T2[string, any]("a", 4), T2[string, any]("a", "foobar"), T2[string, any]("b", 9.6), T2[string, any]("b", 4), T2[string, any]("b", "foobar"), T2[string, any]("c", 9.6), T2[string, any]("c", 4), T2[string, any]("c", "foobar")}, results7)
}
func TestCrossJoinBy(t *testing.T) {
t.Parallel()
is := assert.New(t)
listOne := []string{"a", "b", "c"}
listTwo := []int{1, 2, 3}
emptyList := []any{}
mixedList := []any{9.6, 4, "foobar"}
results1 := CrossJoinBy2(emptyList, listTwo, T2[any, int])
is.Len(results1, 0)
results2 := CrossJoinBy2(listOne, emptyList, T2[string, any])
is.Len(results2, 0)
results3 := CrossJoinBy2(emptyList, emptyList, T2[any, any])
is.Len(results3, 0)
results4 := CrossJoinBy2([]string{"a"}, listTwo, T2[string, int])
is.Equal([]Tuple2[string, int]{T2("a", 1), T2("a", 2), T2("a", 3)}, results4)
results5 := CrossJoinBy2(listOne, []int{1}, T2[string, int])
is.Equal([]Tuple2[string, int]{T2("a", 1), T2("b", 1), T2("c", 1)}, results5)
results6 := CrossJoinBy2(listOne, listTwo, T2[string, int])
is.Equal([]Tuple2[string, int]{T2("a", 1), T2("a", 2), T2("a", 3), T2("b", 1), T2("b", 2), T2("b", 3), T2("c", 1), T2("c", 2), T2("c", 3)}, results6)
results7 := CrossJoinBy2(listOne, mixedList, T2[string, any])
is.Equal([]Tuple2[string, any]{T2[string, any]("a", 9.6), T2[string, any]("a", 4), T2[string, any]("a", "foobar"), T2[string, any]("b", 9.6), T2[string, any]("b", 4), T2[string, any]("b", "foobar"), T2[string, any]("c", 9.6), T2[string, any]("c", 4), T2[string, any]("c", "foobar")}, results7)
}