From 052594bf00bd5745c0b424eb01bf26cb248997f0 Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Sun, 28 Apr 2024 03:11:41 +0200 Subject: [PATCH] feat: adding zipby + unzipby --- tuples.go | 364 +++++++++++++++++++++++++++++++++++++++++++++++++ tuples_test.go | 180 +++++++++++++++++++++++- 2 files changed, 543 insertions(+), 1 deletion(-) diff --git a/tuples.go b/tuples.go index cdddf6af..8d5b7b16 100644 --- a/tuples.go +++ b/tuples.go @@ -328,6 +328,178 @@ func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, return result } +// ZipBy2 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy2[A any, B any, Out any](a []A, b []B, iteratee func(a A, b B) Out) []Out { + size := Max([]int{len(a), len(b)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + + result = append(result, iteratee(_a, _b)) + } + + return result +} + +// ZipBy3 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy3[A any, B any, C any, Out any](a []A, b []B, c []C, iteratee func(a A, b B, c C) Out) []Out { + size := Max([]int{len(a), len(b), len(c)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + + result = append(result, iteratee(_a, _b, _c)) + } + + return result +} + +// ZipBy4 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy4[A any, B any, C any, D any, Out any](a []A, b []B, c []C, d []D, iteratee func(a A, b B, c C, d D) Out) []Out { + size := Max([]int{len(a), len(b), len(c), len(d)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + _d, _ := Nth(d, index) + + result = append(result, iteratee(_a, _b, _c, _d)) + } + + return result +} + +// ZipBy5 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy5[A any, B any, C any, D any, E any, Out any](a []A, b []B, c []C, d []D, e []E, iteratee func(a A, b B, c C, d D, e E) Out) []Out { + size := Max([]int{len(a), len(b), len(c), len(d), len(e)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + _d, _ := Nth(d, index) + _e, _ := Nth(e, index) + + result = append(result, iteratee(_a, _b, _c, _d, _e)) + } + + return result +} + +// ZipBy6 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy6[A any, B any, C any, D any, E any, F any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, iteratee func(a A, b B, c C, d D, e E, f F) Out) []Out { + size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + _d, _ := Nth(d, index) + _e, _ := Nth(e, index) + _f, _ := Nth(f, index) + + result = append(result, iteratee(_a, _b, _c, _d, _e, _f)) + } + + return result +} + +// ZipBy7 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy7[A any, B any, C any, D any, E any, F any, G any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, iteratee func(a A, b B, c C, d D, e E, f F, g G) Out) []Out { + size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + _d, _ := Nth(d, index) + _e, _ := Nth(e, index) + _f, _ := Nth(f, index) + _g, _ := Nth(g, index) + + result = append(result, iteratee(_a, _b, _c, _d, _e, _f, _g)) + } + + return result +} + +// ZipBy8 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy8[A any, B any, C any, D any, E any, F any, G any, H any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, iteratee func(a A, b B, c C, d D, e E, f F, g G, h H) Out) []Out { + size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + _d, _ := Nth(d, index) + _e, _ := Nth(e, index) + _f, _ := Nth(f, index) + _g, _ := Nth(g, index) + _h, _ := Nth(h, index) + + result = append(result, iteratee(_a, _b, _c, _d, _e, _f, _g, _h)) + } + + return result +} + +// ZipBy9 creates a slice of transformed elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func ZipBy9[A any, B any, C any, D any, E any, F any, G any, H any, I any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I, iteratee func(a A, b B, c C, d D, e E, f F, g G, h H, i I) Out) []Out { + size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i)}) + + result := make([]Out, 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth(a, index) + _b, _ := Nth(b, index) + _c, _ := Nth(c, index) + _d, _ := Nth(d, index) + _e, _ := Nth(e, index) + _f, _ := Nth(f, index) + _g, _ := Nth(g, index) + _h, _ := Nth(h, index) + _i, _ := Nth(i, index) + + result = append(result, iteratee(_a, _b, _c, _d, _e, _f, _g, _h, _i)) + } + + return result +} + // Unzip2 accepts an array of grouped elements and creates an array regrouping the elements // to their pre-zip configuration. // Play: https://go.dev/play/p/ciHugugvaAW @@ -511,3 +683,195 @@ func Unzip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuple return r1, r2, r3, r4, r5, r6, r7, r8, r9 } + +// UnzipBy2 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy2[In any, A any, B any](items []In, iteratee func(In) (a A, b B)) ([]A, []B) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + + for _, item := range items { + a, b := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + } + + return r1, r2 +} + +// UnzipBy3 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy3[In any, A any, B any, C any](items []In, iteratee func(In) (a A, b B, c C)) ([]A, []B, []C) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + + for _, item := range items { + a, b, c := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + } + + return r1, r2, r3 +} + +// UnzipBy4 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy4[In any, A any, B any, C any, D any](items []In, iteratee func(In) (a A, b B, c C, d D)) ([]A, []B, []C, []D) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + + for _, item := range items { + a, b, c, d := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + r4 = append(r4, d) + } + + return r1, r2, r3, r4 +} + +// UnzipBy5 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy5[In any, A any, B any, C any, D any, E any](items []In, iteratee func(In) (a A, b B, c C, d D, e E)) ([]A, []B, []C, []D, []E) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + + for _, item := range items { + a, b, c, d, e := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + r4 = append(r4, d) + r5 = append(r5, e) + } + + return r1, r2, r3, r4, r5 +} + +// UnzipBy6 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy6[In any, A any, B any, C any, D any, E any, F any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F)) ([]A, []B, []C, []D, []E, []F) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + + for _, item := range items { + a, b, c, d, e, f := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + r4 = append(r4, d) + r5 = append(r5, e) + r6 = append(r6, f) + } + + return r1, r2, r3, r4, r5, r6 +} + +// UnzipBy7 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy7[In any, A any, B any, C any, D any, E any, F any, G any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G)) ([]A, []B, []C, []D, []E, []F, []G) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + r7 := make([]G, 0, size) + + for _, item := range items { + a, b, c, d, e, f, g := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + r4 = append(r4, d) + r5 = append(r5, e) + r6 = append(r6, f) + r7 = append(r7, g) + } + + return r1, r2, r3, r4, r5, r6, r7 +} + +// UnzipBy8 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy8[In any, A any, B any, C any, D any, E any, F any, G any, H any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G, h H)) ([]A, []B, []C, []D, []E, []F, []G, []H) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + r7 := make([]G, 0, size) + r8 := make([]H, 0, size) + + for _, item := range items { + a, b, c, d, e, f, g, h := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + r4 = append(r4, d) + r5 = append(r5, e) + r6 = append(r6, f) + r7 = append(r7, g) + r8 = append(r8, h) + } + + return r1, r2, r3, r4, r5, r6, r7, r8 +} + +// UnzipBy9 iterate over a collection and creates an array regrouping the elements +// to their pre-zip configuration. +// Play: https://go.dev/play/p/ciHugugvaAW +func UnzipBy9[In any, A any, B any, C any, D any, E any, F any, G any, H any, I any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G, h H, i I)) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) { + size := len(items) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + r7 := make([]G, 0, size) + r8 := make([]H, 0, size) + r9 := make([]I, 0, size) + + for _, item := range items { + a, b, c, d, e, f, g, h, i := iteratee(item) + r1 = append(r1, a) + r2 = append(r2, b) + r3 = append(r3, c) + r4 = append(r4, d) + r5 = append(r5, e) + r6 = append(r6, f) + r7 = append(r7, g) + r8 = append(r8, h) + r9 = append(r9, i) + } + + return r1, r2, r3, r4, r5, r6, r7, r8, r9 +} diff --git a/tuples_test.go b/tuples_test.go index b5aac617..fccf88cf 100644 --- a/tuples_test.go +++ b/tuples_test.go @@ -213,7 +213,8 @@ func TestZip(t *testing.T) { r2 := Zip3( []string{"a", "b", "c"}, - []int{1, 2, 3}, []int{4, 5, 6}, + []int{1, 2, 3}, + []int{4, 5, 6}, ) r3 := Zip4( @@ -342,6 +343,171 @@ func TestZip(t *testing.T) { }) } +func TestZipBy(t *testing.T) { + t.Parallel() + is := assert.New(t) + + r1 := ZipBy2( + []string{"a", "b"}, + []int{1, 2}, + func(a string, b int) Tuple2[string, int] { + return T2(a, b) + }, + ) + + r2 := ZipBy3( + []string{"a", "b", "c"}, + []int{1, 2, 3}, + []int{4, 5, 6}, + func(a string, b int, c int) Tuple3[string, int, int] { + return T3(a, b, c) + }, + ) + + r3 := ZipBy4( + []string{"a", "b", "c", "d"}, + []int{1, 2, 3, 4}, + []int{5, 6, 7, 8}, + []bool{true, true, true, true}, + func(a string, b int, c int, d bool) Tuple4[string, int, int, bool] { + return T4(a, b, c, d) + }, + ) + + r4 := ZipBy5( + []string{"a", "b", "c", "d", "e"}, + []int{1, 2, 3, 4, 5}, + []int{6, 7, 8, 9, 10}, + []bool{true, true, true, true, true}, + []float32{0.1, 0.2, 0.3, 0.4, 0.5}, + func(a string, b int, c int, d bool, e float32) Tuple5[string, int, int, bool, float32] { + return T5(a, b, c, d, e) + }, + ) + + r5 := ZipBy6( + []string{"a", "b", "c", "d", "e", "f"}, + []int{1, 2, 3, 4, 5, 6}, + []int{7, 8, 9, 10, 11, 12}, + []bool{true, true, true, true, true, true}, + []float32{0.1, 0.2, 0.3, 0.4, 0.5, 0.6}, + []float64{0.01, 0.02, 0.03, 0.04, 0.05, 0.06}, + func(a string, b int, c int, d bool, e float32, f float64) Tuple6[string, int, int, bool, float32, float64] { + return T6(a, b, c, d, e, f) + }, + ) + + r6 := ZipBy7( + []string{"a", "b", "c", "d", "e", "f", "g"}, + []int{1, 2, 3, 4, 5, 6, 7}, + []int{8, 9, 10, 11, 12, 13, 14}, + []bool{true, true, true, true, true, true, true}, + []float32{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7}, + []float64{0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07}, + []int8{1, 2, 3, 4, 5, 6, 7}, + func(a string, b int, c int, d bool, e float32, f float64, g int8) Tuple7[string, int, int, bool, float32, float64, int8] { + return T7(a, b, c, d, e, f, g) + }, + ) + + r7 := ZipBy8( + []string{"a", "b", "c", "d", "e", "f", "g", "h"}, + []int{1, 2, 3, 4, 5, 6, 7, 8}, + []int{9, 10, 11, 12, 13, 14, 15, 16}, + []bool{true, true, true, true, true, true, true, true}, + []float32{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}, + []float64{0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08}, + []int8{1, 2, 3, 4, 5, 6, 7, 8}, + []int16{1, 2, 3, 4, 5, 6, 7, 8}, + func(a string, b int, c int, d bool, e float32, f float64, g int8, h int16) Tuple8[string, int, int, bool, float32, float64, int8, int16] { + return T8(a, b, c, d, e, f, g, h) + }, + ) + + r8 := ZipBy9( + []string{"a", "b", "c", "d", "e", "f", "g", "h", "i"}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + []int{10, 11, 12, 13, 14, 15, 16, 17, 18}, + []bool{true, true, true, true, true, true, true, true, true}, + []float32{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}, + []float64{0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09}, + []int8{1, 2, 3, 4, 5, 6, 7, 8, 9}, + []int16{1, 2, 3, 4, 5, 6, 7, 8, 9}, + []int32{1, 2, 3, 4, 5, 6, 7, 8, 9}, + func(a string, b int, c int, d bool, e float32, f float64, g int8, h int16, i int32) Tuple9[string, int, int, bool, float32, float64, int8, int16, int32] { + return T9(a, b, c, d, e, f, g, h, i) + }, + ) + + is.Equal(r1, []Tuple2[string, int]{ + {A: "a", B: 1}, + {A: "b", B: 2}, + }) + + is.Equal(r2, []Tuple3[string, int, int]{ + {A: "a", B: 1, C: 4}, + {A: "b", B: 2, C: 5}, + {A: "c", B: 3, C: 6}, + }) + + is.Equal(r3, []Tuple4[string, int, int, bool]{ + {A: "a", B: 1, C: 5, D: true}, + {A: "b", B: 2, C: 6, D: true}, + {A: "c", B: 3, C: 7, D: true}, + {A: "d", B: 4, C: 8, D: true}, + }) + + is.Equal(r4, []Tuple5[string, int, int, bool, float32]{ + {A: "a", B: 1, C: 6, D: true, E: 0.1}, + {A: "b", B: 2, C: 7, D: true, E: 0.2}, + {A: "c", B: 3, C: 8, D: true, E: 0.3}, + {A: "d", B: 4, C: 9, D: true, E: 0.4}, + {A: "e", B: 5, C: 10, D: true, E: 0.5}, + }) + + is.Equal(r5, []Tuple6[string, int, int, bool, float32, float64]{ + {A: "a", B: 1, C: 7, D: true, E: 0.1, F: 0.01}, + {A: "b", B: 2, C: 8, D: true, E: 0.2, F: 0.02}, + {A: "c", B: 3, C: 9, D: true, E: 0.3, F: 0.03}, + {A: "d", B: 4, C: 10, D: true, E: 0.4, F: 0.04}, + {A: "e", B: 5, C: 11, D: true, E: 0.5, F: 0.05}, + {A: "f", B: 6, C: 12, D: true, E: 0.6, F: 0.06}, + }) + + is.Equal(r6, []Tuple7[string, int, int, bool, float32, float64, int8]{ + {A: "a", B: 1, C: 8, D: true, E: 0.1, F: 0.01, G: 1}, + {A: "b", B: 2, C: 9, D: true, E: 0.2, F: 0.02, G: 2}, + {A: "c", B: 3, C: 10, D: true, E: 0.3, F: 0.03, G: 3}, + {A: "d", B: 4, C: 11, D: true, E: 0.4, F: 0.04, G: 4}, + {A: "e", B: 5, C: 12, D: true, E: 0.5, F: 0.05, G: 5}, + {A: "f", B: 6, C: 13, D: true, E: 0.6, F: 0.06, G: 6}, + {A: "g", B: 7, C: 14, D: true, E: 0.7, F: 0.07, G: 7}, + }) + + is.Equal(r7, []Tuple8[string, int, int, bool, float32, float64, int8, int16]{ + {A: "a", B: 1, C: 9, D: true, E: 0.1, F: 0.01, G: 1, H: 1}, + {A: "b", B: 2, C: 10, D: true, E: 0.2, F: 0.02, G: 2, H: 2}, + {A: "c", B: 3, C: 11, D: true, E: 0.3, F: 0.03, G: 3, H: 3}, + {A: "d", B: 4, C: 12, D: true, E: 0.4, F: 0.04, G: 4, H: 4}, + {A: "e", B: 5, C: 13, D: true, E: 0.5, F: 0.05, G: 5, H: 5}, + {A: "f", B: 6, C: 14, D: true, E: 0.6, F: 0.06, G: 6, H: 6}, + {A: "g", B: 7, C: 15, D: true, E: 0.7, F: 0.07, G: 7, H: 7}, + {A: "h", B: 8, C: 16, D: true, E: 0.8, F: 0.08, G: 8, H: 8}, + }) + + is.Equal(r8, []Tuple9[string, int, int, bool, float32, float64, int8, int16, int32]{ + {A: "a", B: 1, C: 10, D: true, E: 0.1, F: 0.01, G: 1, H: 1, I: 1}, + {A: "b", B: 2, C: 11, D: true, E: 0.2, F: 0.02, G: 2, H: 2, I: 2}, + {A: "c", B: 3, C: 12, D: true, E: 0.3, F: 0.03, G: 3, H: 3, I: 3}, + {A: "d", B: 4, C: 13, D: true, E: 0.4, F: 0.04, G: 4, H: 4, I: 4}, + {A: "e", B: 5, C: 14, D: true, E: 0.5, F: 0.05, G: 5, H: 5, I: 5}, + {A: "f", B: 6, C: 15, D: true, E: 0.6, F: 0.06, G: 6, H: 6, I: 6}, + {A: "g", B: 7, C: 16, D: true, E: 0.7, F: 0.07, G: 7, H: 7, I: 7}, + {A: "h", B: 8, C: 17, D: true, E: 0.8, F: 0.08, G: 8, H: 8, I: 8}, + {A: "i", B: 9, C: 18, D: true, E: 0.9, F: 0.09, G: 9, H: 9, I: 9}, + }) +} + func TestUnzip(t *testing.T) { t.Parallel() is := assert.New(t) @@ -351,3 +517,15 @@ func TestUnzip(t *testing.T) { is.Equal(r1, []string{"a", "b"}) is.Equal(r2, []int{1, 2}) } + +func TestUnzipBy(t *testing.T) { + t.Parallel() + is := assert.New(t) + + r1, r2 := UnzipBy2([]Tuple2[string, int]{{A: "a", B: 1}, {A: "b", B: 2}}, func(i Tuple2[string, int]) (a string, b int) { + return i.A + i.A, i.B + i.B + }) + + is.Equal(r1, []string{"aa", "bb"}) + is.Equal(r2, []int{2, 4}) +}