Skip to content

Commit

Permalink
CrossJoinX + CrossJoinByX
Browse files Browse the repository at this point in the history
  • Loading branch information
samber committed Jan 24, 2025
1 parent c4ae516 commit 2876510
Show file tree
Hide file tree
Showing 6 changed files with 758 additions and 69 deletions.
46 changes: 32 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ Supported helpers for slices:
- [IsSorted](#issorted)
- [IsSortedByKey](#issortedbykey)
- [Splice](#Splice)
- [CrossJoin](#CrossJoin)

Supported helpers for maps:

Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
24 changes: 0 additions & 24 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
31 changes: 0 additions & 31 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Loading

0 comments on commit 2876510

Please sign in to comment.