diff --git a/pkg/internal/README.md b/pkg/internal/README.md
index 00d0189..d09d61e 100644
--- a/pkg/internal/README.md
+++ b/pkg/internal/README.md
@@ -60,6 +60,26 @@ type Ordered interface {
}
```
+# utils
+
+```go
+import "github.com/dashjay/xiter/pkg/internal/utils"
+```
+
+## Index
+
+- [func IsZero\[T comparable\]\(v T\) bool](<#IsZero>)
+
+
+
+## func [IsZero]()
+
+```go
+func IsZero[T comparable](v T) bool
+```
+
+
+
# xassert
```go
diff --git a/pkg/internal/utils/utils.go b/pkg/internal/utils/utils.go
new file mode 100644
index 0000000..85ff544
--- /dev/null
+++ b/pkg/internal/utils/utils.go
@@ -0,0 +1,6 @@
+package utils
+
+func IsZero[T comparable](v T) bool {
+ var zero T
+ return v == zero
+}
diff --git a/pkg/xiter/README.md b/pkg/xiter/README.md
index 9d7ee33..3becc14 100644
--- a/pkg/xiter/README.md
+++ b/pkg/xiter/README.md
@@ -22,34 +22,45 @@ WARNING: golang 1.23 has higher performance on iterating Seq/Seq2 which boost by
- [func ContainsAny\[T comparable\]\(seq Seq\[T\], in \[\]T\) bool](<#ContainsAny>)
- [func ContainsBy\[T any\]\(seq Seq\[T\], f func\(T\) bool\) bool](<#ContainsBy>)
- [func Count\[T any\]\(seq Seq\[T\]\) int](<#Count>)
+- [func Difference\[T comparable\]\(left Seq\[T\], right Seq\[T\]\) \(onlyLeft Seq\[T\], onlyRight Seq\[T\]\)](<#Difference>)
- [func Equal\[V comparable\]\(x, y Seq\[V\]\) bool](<#Equal>)
- [func Equal2\[K, V comparable\]\(x, y Seq2\[K, V\]\) bool](<#Equal2>)
- [func EqualFunc\[V1, V2 any\]\(x Seq\[V1\], y Seq\[V2\], f func\(V1, V2\) bool\) bool](<#EqualFunc>)
- [func EqualFunc2\[K1, V1, K2, V2 any\]\(x Seq2\[K1, V1\], y Seq2\[K2, V2\], f func\(K1, V1, K2, V2\) bool\) bool](<#EqualFunc2>)
- [func Find\[T any\]\(seq Seq\[T\], f func\(T\) bool\) \(val T, found bool\)](<#Find>)
- [func FindO\[T any\]\(seq Seq\[T\], f func\(T\) bool\) optional.O\[T\]](<#FindO>)
+- [func First\[T any\]\(in Seq\[T\]\) \(T, bool\)](<#First>)
+- [func FirstO\[T any\]\(in Seq\[T\]\) optional.O\[T\]](<#FirstO>)
- [func ForEach\[T any\]\(seq Seq\[T\], f func\(T\) bool\)](<#ForEach>)
- [func ForEachIdx\[T any\]\(seq Seq\[T\], f func\(idx int, v T\) bool\)](<#ForEachIdx>)
- [func Head\[T any\]\(seq Seq\[T\]\) \(v T, hasOne bool\)](<#Head>)
- [func HeadO\[T any\]\(seq Seq\[T\]\) optional.O\[T\]](<#HeadO>)
- [func Index\[T comparable\]\(seq Seq\[T\], v T\) int](<#Index>)
- [func Join\[T \~string\]\(seq Seq\[T\], sep T\) T](<#Join>)
+- [func Last\[T any\]\(in Seq\[T\]\) \(T, bool\)](<#Last>)
+- [func LastO\[T any\]\(in Seq\[T\]\) optional.O\[T\]](<#LastO>)
- [func Max\[T constraints.Ordered\]\(seq Seq\[T\]\) \(r optional.O\[T\]\)](<#Max>)
- [func MaxBy\[T constraints.Ordered\]\(seq Seq\[T\], less func\(T, T\) bool\) \(r optional.O\[T\]\)](<#MaxBy>)
+- [func Mean\[T constraints.Number\]\(in Seq\[T\]\) T](<#Mean>)
+- [func MeanBy\[T any, R constraints.Number\]\(in Seq\[T\], fn func\(T\) R\) R](<#MeanBy>)
- [func Min\[T constraints.Ordered\]\(seq Seq\[T\]\) \(r optional.O\[T\]\)](<#Min>)
- [func MinBy\[T constraints.Ordered\]\(seq Seq\[T\], less func\(T, T\) bool\) \(r optional.O\[T\]\)](<#MinBy>)
+- [func Moderate\[T comparable\]\(in Seq\[T\]\) \(T, bool\)](<#Moderate>)
+- [func ModerateO\[T constraints.Number\]\(in Seq\[T\]\) optional.O\[T\]](<#ModerateO>)
- [func Pull\[V any\]\(seq Seq\[V\]\) \(next func\(\) \(V, bool\), stop func\(\)\)](<#Pull>)
- [func Pull2\[K, V any\]\(seq Seq2\[K, V\]\) \(next func\(\) \(K, V, bool\), stop func\(\)\)](<#Pull2>)
- [func Reduce\[Sum, V any\]\(f func\(Sum, V\) Sum, sum Sum, seq Seq\[V\]\) Sum](<#Reduce>)
- [func Reduce2\[Sum, K, V any\]\(f func\(Sum, K, V\) Sum, sum Sum, seq Seq2\[K, V\]\) Sum](<#Reduce2>)
- [func Sum\[T constraints.Number\]\(seq Seq\[T\]\) T](<#Sum>)
- [func ToMap\[K comparable, V any\]\(seq Seq2\[K, V\]\) \(out map\[K\]V\)](<#ToMap>)
+- [func ToMapFromSeq\[K comparable, V any\]\(seq Seq\[K\], fn func\(k K\) V\) \(out map\[K\]V\)](<#ToMapFromSeq>)
- [func ToSlice\[T any\]\(seq Seq\[T\]\) \(out \[\]T\)](<#ToSlice>)
- [func ToSliceN\[T any\]\(seq Seq\[T\], n int\) \(out \[\]T\)](<#ToSliceN>)
- [func ToSliceSeq2Key\[K, V any\]\(seq Seq2\[K, V\]\) \(out \[\]K\)](<#ToSliceSeq2Key>)
- [func ToSliceSeq2Value\[K, V any\]\(seq Seq2\[K, V\]\) \(out \[\]V\)](<#ToSliceSeq2Value>)
- [type Seq](<#Seq>)
- [func Chunk\[T any\]\(seq Seq\[T\], n int\) Seq\[\[\]T\]](<#Chunk>)
+ - [func Compact\[T comparable\]\(in Seq\[T\]\) Seq\[T\]](<#Compact>)
- [func Concat\[V any\]\(seqs ...Seq\[V\]\) Seq\[V\]](<#Concat>)
- [func Filter\[V any\]\(f func\(V\) bool, seq Seq\[V\]\) Seq\[V\]](<#Filter>)
- [func FromChan\[T any\]\(in \<\-chan T\) Seq\[T\]](<#FromChan>)
@@ -58,6 +69,7 @@ WARNING: golang 1.23 has higher performance on iterating Seq/Seq2 which boost by
- [func FromSlice\[T any\]\(in \[\]T\) Seq\[T\]](<#FromSlice>)
- [func FromSliceReverse\[T any, Slice \~\[\]T\]\(in Slice\) Seq\[T\]](<#FromSliceReverse>)
- [func FromSliceShuffle\[T any\]\(in \[\]T\) Seq\[T\]](<#FromSliceShuffle>)
+ - [func Intersect\[T comparable\]\(left Seq\[T\], right Seq\[T\]\) Seq\[T\]](<#Intersect>)
- [func Limit\[V any\]\(seq Seq\[V\], n int\) Seq\[V\]](<#Limit>)
- [func Map\[In, Out any\]\(f func\(In\) Out, seq Seq\[In\]\) Seq\[Out\]](<#Map>)
- [func Merge\[V cmp.Ordered\]\(x, y Seq\[V\]\) Seq\[V\]](<#Merge>)
@@ -70,6 +82,7 @@ WARNING: golang 1.23 has higher performance on iterating Seq/Seq2 which boost by
- [func Seq2ToSeqUnion\[K, V any\]\(seq Seq2\[K, V\]\) Seq\[union.U2\[K, V\]\]](<#Seq2ToSeqUnion>)
- [func Seq2ValueToSeq\[K, V any\]\(in Seq2\[K, V\]\) Seq\[V\]](<#Seq2ValueToSeq>)
- [func Skip\[T any\]\(seq Seq\[T\], n int\) Seq\[T\]](<#Skip>)
+ - [func Union\[T comparable\]\(left, right Seq\[T\]\) Seq\[T\]](<#Union>)
- [func Uniq\[T comparable\]\(seq Seq\[T\]\) Seq\[T\]](<#Uniq>)
- [func Zip\[V1, V2 any\]\(x Seq\[V1\], y Seq\[V2\]\) Seq\[Zipped\[V1, V2\]\]](<#Zip>)
- [func Zip2\[K1, V1, K2, V2 any\]\(x Seq2\[K1, V1\], y Seq2\[K2, V2\]\) Seq\[Zipped2\[K1, V1, K2, V2\]\]](<#Zip2>)
@@ -89,7 +102,7 @@ WARNING: golang 1.23 has higher performance on iterating Seq/Seq2 which boost by
-## func [AllFromSeq]()
+## func [AllFromSeq]()
```go
func AllFromSeq[T any](seq Seq[T], f func(T) bool) bool
@@ -98,7 +111,7 @@ func AllFromSeq[T any](seq Seq[T], f func(T) bool) bool
AllFromSeq return true if all elements from seq satisfy the condition evaluated by f.
-## func [AnyFromSeq]()
+## func [AnyFromSeq]()
```go
func AnyFromSeq[T any](seq Seq[T], f func(T) bool) bool
@@ -107,7 +120,7 @@ func AnyFromSeq[T any](seq Seq[T], f func(T) bool) bool
AnyFromSeq return true if any elements from seq satisfy the condition evaluated by f.
-## func [At]()
+## func [At]()
```go
func At[T any](seq Seq[T], index int) optional.O[T]
@@ -116,7 +129,7 @@ func At[T any](seq Seq[T], index int) optional.O[T]
At return the element at index from seq.
-## func [AvgByFromSeq]()
+## func [AvgByFromSeq]()
```go
func AvgByFromSeq[V any, T constraints.Number](seq Seq[V], f func(V) T) float64
@@ -125,7 +138,7 @@ func AvgByFromSeq[V any, T constraints.Number](seq Seq[V], f func(V) T) float64
AvgByFromSeq return the average value of all elements from seq, evaluated by f.
-## func [AvgFromSeq]()
+## func [AvgFromSeq]()
```go
func AvgFromSeq[T constraints.Number](seq Seq[T]) float64
@@ -134,7 +147,7 @@ func AvgFromSeq[T constraints.Number](seq Seq[T]) float64
AvgFromSeq return the average value of all elements from seq.
-## func [Contains]()
+## func [Contains]()
```go
func Contains[T comparable](seq Seq[T], in T) bool
@@ -143,7 +156,7 @@ func Contains[T comparable](seq Seq[T], in T) bool
Contains return true if v is in seq.
-## func [ContainsAll]()
+## func [ContainsAll]()
```go
func ContainsAll[T comparable](seq Seq[T], in []T) bool
@@ -152,7 +165,7 @@ func ContainsAll[T comparable](seq Seq[T], in []T) bool
ContainsAll return true if all elements from seq is in vs.
-## func [ContainsAny]()
+## func [ContainsAny]()
```go
func ContainsAny[T comparable](seq Seq[T], in []T) bool
@@ -161,7 +174,7 @@ func ContainsAny[T comparable](seq Seq[T], in []T) bool
ContainsAny return true if any element from seq is in vs.
-## func [ContainsBy]()
+## func [ContainsBy]()
```go
func ContainsBy[T any](seq Seq[T], f func(T) bool) bool
@@ -170,7 +183,7 @@ func ContainsBy[T any](seq Seq[T], f func(T) bool) bool
ContainsBy return true if any element from seq satisfies the condition evaluated by f.
-## func [Count]()
+## func [Count]()
```go
func Count[T any](seq Seq[T]) int
@@ -178,8 +191,27 @@ func Count[T any](seq Seq[T]) int
Count return the number of elements in seq.
+
+## func [Difference]()
+
+```go
+func Difference[T comparable](left Seq[T], right Seq[T]) (onlyLeft Seq[T], onlyRight Seq[T])
+```
+
+Difference returns two sequences: the first sequence contains elements that are in the left sequence but not in the right sequence, and the second sequence contains elements that are in the right sequence but not in the left sequence.
+
+EXAMPLE:
+
+```
+left := []int{1, 2, 3, 4}
+right := []int{3, 4, 5, 6}
+onlyLeft, onlyRight := Difference(FromSlice(left), FromSlice(right))
+// onlyLeft 👉 [1 2]
+// onlyRight 👉 [5 6]
+```
+
-## func [Equal]()
+## func [Equal]()
```go
func Equal[V comparable](x, y Seq[V]) bool
@@ -234,7 +266,7 @@ false
-## func [Equal2]()
+## func [Equal2]()
```go
func Equal2[K, V comparable](x, y Seq2[K, V]) bool
@@ -243,7 +275,7 @@ func Equal2[K, V comparable](x, y Seq2[K, V]) bool
Equal2 returns whether the two Seq2 are equal. Like Equal but run with Seq2
-## func [EqualFunc]()
+## func [EqualFunc]()
```go
func EqualFunc[V1, V2 any](x Seq[V1], y Seq[V2], f func(V1, V2) bool) bool
@@ -303,7 +335,7 @@ false
-## func [EqualFunc2]()
+## func [EqualFunc2]()
```go
func EqualFunc2[K1, V1, K2, V2 any](x Seq2[K1, V1], y Seq2[K2, V2], f func(K1, V1, K2, V2) bool) bool
@@ -312,7 +344,7 @@ func EqualFunc2[K1, V1, K2, V2 any](x Seq2[K1, V1], y Seq2[K2, V2], f func(K1, V
EqualFunc2 returns whether the two sequences are equal according to the function f. Like EqualFunc but run with Seq2
-## func [Find]()
+## func [Find]()
```go
func Find[T any](seq Seq[T], f func(T) bool) (val T, found bool)
@@ -321,7 +353,7 @@ func Find[T any](seq Seq[T], f func(T) bool) (val T, found bool)
Find return the first element from seq that satisfies the condition evaluated by f with a boolean representing whether it exists.
-## func [FindO]()
+## func [FindO]()
```go
func FindO[T any](seq Seq[T], f func(T) bool) optional.O[T]
@@ -329,8 +361,38 @@ func FindO[T any](seq Seq[T], f func(T) bool) optional.O[T]
FindO return the first element from seq that satisfies the condition evaluated by f.
+
+## func [First]()
+
+```go
+func First[T any](in Seq[T]) (T, bool)
+```
+
+First returns the first element in the sequence. If the sequence is empty, the zero value of T is returned. Example:
+
+```
+seq := FromSlice([]int{1, 2, 3})
+first, ok := First(seq)
+// first is 1, ok is true
+```
+
+
+## func [FirstO]()
+
+```go
+func FirstO[T any](in Seq[T]) optional.O[T]
+```
+
+FirstO returns the first element in the sequence as an optional.O\[T\]. If the sequence is empty, the zero value of T is returned. Example:
+
+```
+seq := FromSlice([]int{1, 2, 3})
+first, ok := FirstO(seq)
+// first is 1, ok is true
+```
+
-## func [ForEach]()
+## func [ForEach]()
```go
func ForEach[T any](seq Seq[T], f func(T) bool)
@@ -339,7 +401,7 @@ func ForEach[T any](seq Seq[T], f func(T) bool)
ForEach execute f for each element in seq.
-## func [ForEachIdx]()
+## func [ForEachIdx]()
```go
func ForEachIdx[T any](seq Seq[T], f func(idx int, v T) bool)
@@ -348,7 +410,7 @@ func ForEachIdx[T any](seq Seq[T], f func(idx int, v T) bool)
ForEachIdx execute f for each element in seq with its index.
-## func [Head]()
+## func [Head]()
```go
func Head[T any](seq Seq[T]) (v T, hasOne bool)
@@ -357,7 +419,7 @@ func Head[T any](seq Seq[T]) (v T, hasOne bool)
Head return the first element from seq with a boolean representing whether it is at least one element in seq.
-## func [HeadO]()
+## func [HeadO]()
```go
func HeadO[T any](seq Seq[T]) optional.O[T]
@@ -366,7 +428,7 @@ func HeadO[T any](seq Seq[T]) optional.O[T]
HeadO return the first element from seq.
-## func [Index]()
+## func [Index]()
```go
func Index[T comparable](seq Seq[T], v T) int
@@ -383,7 +445,7 @@ idx := xiter.Index(seq, 3)
```
-## func [Join]()
+## func [Join]()
```go
func Join[T ~string](seq Seq[T], sep T) T
@@ -391,8 +453,38 @@ func Join[T ~string](seq Seq[T], sep T) T
Join return the concatenation of all elements in seq with sep.
+
+## func [Last]()
+
+```go
+func Last[T any](in Seq[T]) (T, bool)
+```
+
+Last returns the last element in the sequence. If the sequence is empty, the zero value of T is returned. Example:
+
+```
+seq := FromSlice([]int{1, 2, 3})
+last, ok := Last(seq)
+// last is 3, ok is true
+```
+
+
+## func [LastO]()
+
+```go
+func LastO[T any](in Seq[T]) optional.O[T]
+```
+
+LastO returns the last element in the sequence as an optional.O\[T\]. If the sequence is empty, the zero value of T is returned. Example:
+
+```
+seq := FromSlice([]int{1, 2, 3})
+last, ok := LastO(seq)
+// last is 3, ok is true
+```
+
-## func [Max]()
+## func [Max]()
```go
func Max[T constraints.Ordered](seq Seq[T]) (r optional.O[T])
@@ -401,7 +493,7 @@ func Max[T constraints.Ordered](seq Seq[T]) (r optional.O[T])
Max returns the maximum element in seq.
-## func [MaxBy]()
+## func [MaxBy]()
```go
func MaxBy[T constraints.Ordered](seq Seq[T], less func(T, T) bool) (r optional.O[T])
@@ -409,8 +501,42 @@ func MaxBy[T constraints.Ordered](seq Seq[T], less func(T, T) bool) (r optional.
MaxBy return the maximum element in seq, evaluated by f.
+
+## func [Mean]()
+
+```go
+func Mean[T constraints.Number](in Seq[T]) T
+```
+
+Mean return the mean of seq.
+
+EXAMPLE:
+
+```
+mean := Mean(FromSlice([]int{1, 2, 3, 4, 5}))
+// mean 👉 3
+```
+
+
+## func [MeanBy]()
+
+```go
+func MeanBy[T any, R constraints.Number](in Seq[T], fn func(T) R) R
+```
+
+MeanBy return the mean of seq by fn.
+
+EXAMPLE:
+
+```
+mean := MeanBy(FromSlice([]int{1, 2, 3, 4, 5}), func(v int) int {
+ return v * 2
+})
+// mean 👉 6
+```
+
-## func [Min]()
+## func [Min]()
```go
func Min[T constraints.Ordered](seq Seq[T]) (r optional.O[T])
@@ -419,7 +545,7 @@ func Min[T constraints.Ordered](seq Seq[T]) (r optional.O[T])
Min return the minimum element in seq.
-## func [MinBy]()
+## func [MinBy]()
```go
func MinBy[T constraints.Ordered](seq Seq[T], less func(T, T) bool) (r optional.O[T])
@@ -427,8 +553,40 @@ func MinBy[T constraints.Ordered](seq Seq[T], less func(T, T) bool) (r optional.
MinBy return the minimum element in seq, evaluated by f.
+
+## func [Moderate]()
+
+```go
+func Moderate[T comparable](in Seq[T]) (T, bool)
+```
+
+Moderate return the most common element in seq.
+
+EXAMPLE:
+
+```
+moderate := Moderate(FromSlice([]int{1, 2, 3, 4, 5, 5, 5, 6, 6, 6, 6}))
+// moderate 👉 6
+```
+
+
+## func [ModerateO]()
+
+```go
+func ModerateO[T constraints.Number](in Seq[T]) optional.O[T]
+```
+
+ModerateO return the most common element in seq.
+
+EXAMPLE:
+
+```
+moderate := ModerateO(FromSlice([]int{1, 2, 3, 4, 5, 5, 5, 6, 6, 6, 6}))
+// moderate 👉 6
+```
+
-## func [Pull]()
+## func [Pull]()
```go
func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func())
@@ -479,7 +637,7 @@ func main() {
-## func [Pull2]()
+## func [Pull2]()
```go
func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func())
@@ -488,7 +646,7 @@ func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func())
-## func [Reduce]()
+## func [Reduce]()
```go
func Reduce[Sum, V any](f func(Sum, V) Sum, sum Sum, seq Seq[V]) Sum
@@ -547,7 +705,7 @@ func main() {
-## func [Reduce2]()
+## func [Reduce2]()
```go
func Reduce2[Sum, K, V any](f func(Sum, K, V) Sum, sum Sum, seq Seq2[K, V]) Sum
@@ -556,7 +714,7 @@ func Reduce2[Sum, K, V any](f func(Sum, K, V) Sum, sum Sum, seq Seq2[K, V]) Sum
Reduce2 combines the values in seq using f. For each pair k, v in seq, it updates sum = f\(sum, k, v\) and then returns the final sum. For example, if iterating over seq yields \(k1, v1\), \(k2, v2\), \(k3, v3\) Reduce returns f\(f\(f\(sum, k1, v1\), k2, v2\), k3, v3\).
-## func [Sum]()
+## func [Sum]()
```go
func Sum[T constraints.Number](seq Seq[T]) T
@@ -573,7 +731,7 @@ sum := xiter.Sum(seq)
```
-## func [ToMap]()
+## func [ToMap]()
```go
func ToMap[K comparable, V any](seq Seq2[K, V]) (out map[K]V)
@@ -581,8 +739,17 @@ func ToMap[K comparable, V any](seq Seq2[K, V]) (out map[K]V)
+
+## func [ToMapFromSeq]()
+
+```go
+func ToMapFromSeq[K comparable, V any](seq Seq[K], fn func(k K) V) (out map[K]V)
+```
+
+
+
-## func [ToSlice]()
+## func [ToSlice]()
```go
func ToSlice[T any](seq Seq[T]) (out []T)
@@ -591,7 +758,7 @@ func ToSlice[T any](seq Seq[T]) (out []T)
ToSlice returns the elements in seq as a slice.
-## func [ToSliceN]()
+## func [ToSliceN]()
```go
func ToSliceN[T any](seq Seq[T], n int) (out []T)
@@ -600,7 +767,7 @@ func ToSliceN[T any](seq Seq[T], n int) (out []T)
ToSliceN pull out n elements from seq.
-## func [ToSliceSeq2Key]()
+## func [ToSliceSeq2Key]()
```go
func ToSliceSeq2Key[K, V any](seq Seq2[K, V]) (out []K)
@@ -617,7 +784,7 @@ keys := ToSliceSeq2Key(seq)
```
-## func [ToSliceSeq2Value]()
+## func [ToSliceSeq2Value]()
```go
func ToSliceSeq2Value[K, V any](seq Seq2[K, V]) (out []V)
@@ -634,7 +801,7 @@ values := ToSliceSeq2Value(seq)
```
-## type [Seq]()
+## type [Seq]()
Seq is a sequence of elements provided by an iterator\-like function. We made this alias Seq to iter.Seq for providing a compatible interface in lower go versions.
@@ -643,7 +810,7 @@ type Seq[V any] iter.Seq[V]
```
-### func [Chunk]()
+### func [Chunk]()
```go
func Chunk[T any](seq Seq[T], n int) Seq[[]T]
@@ -659,8 +826,23 @@ chunkedSeq := xiter.Chunk(seq, 2)
// xiter.ToSlice(chunkedSeq) returns [][]int{{1,2}, {3,4}, {5}}
```
+
+### func [Compact]()
+
+```go
+func Compact[T comparable](in Seq[T]) Seq[T]
+```
+
+Compact returns a new sequence with the zero elements removed.
+
+EXAMPLE:
+
+```
+Compact([]int{0, 1, 2, 3, 4}) 👉 [1 2 3 4]
+```
+
-### func [Concat]()
+### func [Concat]()
```go
func Concat[V any](seqs ...Seq[V]) Seq[V]
@@ -713,7 +895,7 @@ func main() {
-### func [Filter]()
+### func [Filter]()
```go
func Filter[V any](f func(V) bool, seq Seq[V]) Seq[V]
@@ -760,7 +942,7 @@ func main() {
-### func [FromChan]()
+### func [FromChan]()
```go
func FromChan[T any](in <-chan T) Seq[T]
@@ -783,7 +965,7 @@ _ = ToSlice(seq) // Returns []int{1, 2}
```
-### func [FromMapKeys]()
+### func [FromMapKeys]()
```go
func FromMapKeys[K comparable, V any](m map[K]V) Seq[K]
@@ -792,7 +974,7 @@ func FromMapKeys[K comparable, V any](m map[K]V) Seq[K]
-### func [FromMapValues]()
+### func [FromMapValues]()
```go
func FromMapValues[K comparable, V any](m map[K]V) Seq[V]
@@ -801,7 +983,7 @@ func FromMapValues[K comparable, V any](m map[K]V) Seq[V]
-### func [FromSlice]()
+### func [FromSlice]()
```go
func FromSlice[T any](in []T) Seq[T]
@@ -810,7 +992,7 @@ func FromSlice[T any](in []T) Seq[T]
FromSlice received a slice and returned a Seq for this slice.
-### func [FromSliceReverse]()
+### func [FromSliceReverse]()
```go
func FromSliceReverse[T any, Slice ~[]T](in Slice) Seq[T]
@@ -819,7 +1001,7 @@ func FromSliceReverse[T any, Slice ~[]T](in Slice) Seq[T]
-### func [FromSliceShuffle]()
+### func [FromSliceShuffle]()
```go
func FromSliceShuffle[T any](in []T) Seq[T]
@@ -835,8 +1017,26 @@ shuffledSeq := FromSliceShuffle(ToSlice(seq))
// shuffledSeq will yield a shuffled sequence of 1, 2, 3, 4, 5
```
+
+### func [Intersect]()
+
+```go
+func Intersect[T comparable](left Seq[T], right Seq[T]) Seq[T]
+```
+
+Intersect return a seq that only contain elements in both left and right.
+
+EXAMPLE:
+
+```
+left := []int{1, 2, 3, 4}
+right := []int{3, 4, 5, 6}
+intersect := Intersect(FromSlice(left), FromSlice(right))
+// intersect 👉 [3 4]
+```
+
-### func [Limit]()
+### func [Limit]()
```go
func Limit[V any](seq Seq[V], n int) Seq[V]
@@ -885,7 +1085,7 @@ func main() {
-### func [Map]()
+### func [Map]()
```go
func Map[In, Out any](f func(In) Out, seq Seq[In]) Seq[Out]
@@ -934,7 +1134,7 @@ func main() {
-### func [Merge]()
+### func [Merge]()
```go
func Merge[V cmp.Ordered](x, y Seq[V]) Seq[V]
@@ -976,7 +1176,7 @@ func main() {
-### func [MergeFunc]()
+### func [MergeFunc]()
```go
func MergeFunc[V any](x, y Seq[V], f func(V, V) int) Seq[V]
@@ -985,7 +1185,7 @@ func MergeFunc[V any](x, y Seq[V], f func(V, V) int) Seq[V]
MergeFunc merges two sequences of values ordered by the function f. Values appear in the output once for each time they appear in x and once for each time they appear in y. When equal values appear in both sequences, the output contains the values from x before the values from y. If the two input sequences are not ordered by f, the output sequence will not be ordered by f, but it will still contain every value from x and y exactly once.
-### func [Repeat]()
+### func [Repeat]()
```go
func Repeat[T any](seq Seq[T], count int) Seq[T]
@@ -994,7 +1194,7 @@ func Repeat[T any](seq Seq[T], count int) Seq[T]
Repeat return a seq that repeat seq for count times.
-### func [Replace]()
+### func [Replace]()
```go
func Replace[T comparable](seq Seq[T], from, to T, n int) Seq[T]
@@ -1011,7 +1211,7 @@ replacedSeq := Replace(seq, 2, 99, -1) // Replace all 2s with 99
```
-### func [ReplaceAll]()
+### func [ReplaceAll]()
```go
func ReplaceAll[T comparable](seq Seq[T], from, to T) Seq[T]
@@ -1028,7 +1228,7 @@ replacedSeq := ReplaceAll(seq, 2, 99)
```
-### func [Reverse]()
+### func [Reverse]()
```go
func Reverse[T any](seq Seq[T]) Seq[T]
@@ -1037,16 +1237,16 @@ func Reverse[T any](seq Seq[T]) Seq[T]
Reverse return a reversed seq.
-### func [Seq2KeyToSeq]()
+### func [Seq2KeyToSeq]()
```go
func Seq2KeyToSeq[K, V any](in Seq2[K, V]) Seq[K]
```
-
+Seq2KeyToSeq return a seq that only contain keys in seq2.
-### func [Seq2ToSeqUnion]()
+### func [Seq2ToSeqUnion]()
```go
func Seq2ToSeqUnion[K, V any](seq Seq2[K, V]) Seq[union.U2[K, V]]
@@ -1064,16 +1264,16 @@ for v := range Seq2ToSeqUnion(seq2) {
```
-### func [Seq2ValueToSeq]()
+### func [Seq2ValueToSeq]()
```go
func Seq2ValueToSeq[K, V any](in Seq2[K, V]) Seq[V]
```
-
+Seq2ValueToSeq return a seq that only contain values in seq2.
-### func [Skip]()
+### func [Skip]()
```go
func Skip[T any](seq Seq[T], n int) Seq[T]
@@ -1081,8 +1281,26 @@ func Skip[T any](seq Seq[T], n int) Seq[T]
Skip return a seq that skip n elements from seq.
+
+### func [Union]()
+
+```go
+func Union[T comparable](left, right Seq[T]) Seq[T]
+```
+
+Union return a seq that contain all elements in left and right.
+
+EXAMPLE:
+
+```
+left := []int{1, 2, 3, 4}
+right := []int{3, 4, 5, 6}
+union := Union(FromSlice(left), FromSlice(right))
+// union 👉 [1 2 3 4 5 6]
+```
+
-### func [Uniq]()
+### func [Uniq]()
```go
func Uniq[T comparable](seq Seq[T]) Seq[T]
@@ -1099,7 +1317,7 @@ uniqSeq := xiter.Uniq(seq)
```
-### func [Zip]()
+### func [Zip]()
```go
func Zip[V1, V2 any](x Seq[V1], y Seq[V2]) Seq[Zipped[V1, V2]]
@@ -1157,7 +1375,7 @@ func main() {
-### func [Zip2]()
+### func [Zip2]()
```go
func Zip2[K1, V1, K2, V2 any](x Seq2[K1, V1], y Seq2[K2, V2]) Seq[Zipped2[K1, V1, K2, V2]]
@@ -1179,7 +1397,7 @@ func Equal2[K, V comparable](x, y Seq2[K, V]) bool {
```
-## type [Seq2]()
+## type [Seq2]()
Seq2 is a sequence of key/value pair provided by an iterator\-like function. We made this alias Seq2 to iter.Seq2 for providing a compatible interface in lower go versions.
@@ -1188,7 +1406,7 @@ type Seq2[K, V any] iter.Seq2[K, V]
```
-### func [Concat2]()
+### func [Concat2]()
```go
func Concat2[K, V any](seqs ...Seq2[K, V]) Seq2[K, V]
@@ -1197,7 +1415,7 @@ func Concat2[K, V any](seqs ...Seq2[K, V]) Seq2[K, V]
Concat2 returns an Seq2 over the concatenation of the given Seq2s. Like Concat but run with Seq2
-### func [Filter2]()
+### func [Filter2]()
```go
func Filter2[K, V any](f func(K, V) bool, seq Seq2[K, V]) Seq2[K, V]
@@ -1206,7 +1424,7 @@ func Filter2[K, V any](f func(K, V) bool, seq Seq2[K, V]) Seq2[K, V]
Filter2 returns an Seq over seq that only includes the key\-value pairs k, v for which f\(k, v\) is true. Like Filter but run with Seq2
-### func [FromMapKeyAndValues]()
+### func [FromMapKeyAndValues]()
```go
func FromMapKeyAndValues[K comparable, V any](m map[K]V) Seq2[K, V]
@@ -1215,7 +1433,7 @@ func FromMapKeyAndValues[K comparable, V any](m map[K]V) Seq2[K, V]
-### func [FromSliceIdx]()
+### func [FromSliceIdx]()
```go
func FromSliceIdx[T any](in []T) Seq2[int, T]
@@ -1224,7 +1442,7 @@ func FromSliceIdx[T any](in []T) Seq2[int, T]
FromSliceIdx received a slice and returned a Seq2 for this slice, key is index.
-### func [Limit2]()
+### func [Limit2]()
```go
func Limit2[K, V any](seq Seq2[K, V], n int) Seq2[K, V]
@@ -1233,7 +1451,7 @@ func Limit2[K, V any](seq Seq2[K, V], n int) Seq2[K, V]
Limit2 returns a Seq over Seq2 that stops after n key\-value pairs. Like Limit but run with Seq2
-### func [Map2]()
+### func [Map2]()
```go
func Map2[KIn, VIn, KOut, VOut any](f func(KIn, VIn) (KOut, VOut), seq Seq2[KIn, VIn]) Seq2[KOut, VOut]
@@ -1242,7 +1460,7 @@ func Map2[KIn, VIn, KOut, VOut any](f func(KIn, VIn) (KOut, VOut), seq Seq2[KIn,
Map2 returns a Seq2 over the results of applying f to each key\-value pair in seq. Like Map but run with Seq2
-### func [MapToSeq2]()
+### func [MapToSeq2]()
```go
func MapToSeq2[T any, K comparable](in Seq[T], mapFn func(ele T) K) Seq2[K, T]
@@ -1263,7 +1481,7 @@ fmt.Println(ToMap(lenMap))
```
-### func [MapToSeq2Value]()
+### func [MapToSeq2Value]()
```go
func MapToSeq2Value[T any, K comparable, V any](in Seq[T], mapFn func(ele T) (K, V)) Seq2[K, V]
@@ -1283,7 +1501,7 @@ fmt.Println(ToMap(transformed))
```
-### func [Merge2]()
+### func [Merge2]()
```go
func Merge2[K cmp.Ordered, V any](x, y Seq2[K, V]) Seq2[K, V]
@@ -1294,7 +1512,7 @@ Merge2 merges two sequences of key\-value pairs ordered by their keys. Pairs app
Merge2 is equivalent to calling MergeFunc2 with cmp.Compare\[K\] as the ordering function.
-### func [MergeFunc2]()
+### func [MergeFunc2]()
```go
func MergeFunc2[K, V any](x, y Seq2[K, V], f func(K, K) int) Seq2[K, V]
@@ -1303,7 +1521,7 @@ func MergeFunc2[K, V any](x, y Seq2[K, V], f func(K, K) int) Seq2[K, V]
MergeFunc2 merges two sequences of key\-value pairs ordered by the function f. Pairs appear in the output once for each time they appear in x and once for each time they appear in y. When pairs with equal keys appear in both sequences, the output contains the pairs from x before the pairs from y. If the two input sequences are not ordered by f, the output sequence will not be ordered by f, but it will still contain every pair from x and y exactly once.
-## type [Zipped]()
+## type [Zipped]()
A Zipped is a pair of zipped values, one of which may be missing, drawn from two different sequences.
@@ -1317,7 +1535,7 @@ type Zipped[V1, V2 any] struct {
```
-## type [Zipped2]()
+## type [Zipped2]()
A Zipped2 is a pair of zipped key\-value pairs, one of which may be missing, drawn from two different sequences.
diff --git a/pkg/xiter/xiter.go b/pkg/xiter/xiter.go
index e45a880..8ec7f73 100644
--- a/pkg/xiter/xiter.go
+++ b/pkg/xiter/xiter.go
@@ -9,6 +9,8 @@ import (
"math/rand"
"strings"
+ "github.com/dashjay/xiter/pkg/internal/utils"
+
"github.com/dashjay/xiter/pkg/cmp"
"github.com/dashjay/xiter/pkg/internal/constraints"
"github.com/dashjay/xiter/pkg/optional"
@@ -478,6 +480,7 @@ func ToSliceSeq2Value[K, V any](seq Seq2[K, V]) (out []V) {
return
}
+// Seq2KeyToSeq return a seq that only contain keys in seq2.
func Seq2KeyToSeq[K, V any](in Seq2[K, V]) Seq[K] {
return func(yield func(K) bool) {
for k := range in {
@@ -488,6 +491,7 @@ func Seq2KeyToSeq[K, V any](in Seq2[K, V]) Seq[K] {
}
}
+// Seq2ValueToSeq return a seq that only contain values in seq2.
func Seq2ValueToSeq[K, V any](in Seq2[K, V]) Seq[V] {
return func(yield func(V) bool) {
for _, v := range in {
@@ -502,6 +506,14 @@ func ToMap[K comparable, V any](seq Seq2[K, V]) (out map[K]V) {
return maps.Collect(iter.Seq2[K, V](seq))
}
+func ToMapFromSeq[K comparable, V any](seq Seq[K], fn func(k K) V) (out map[K]V) {
+ out = make(map[K]V)
+ for k := range seq {
+ out[k] = fn(k)
+ }
+ return out
+}
+
func FromMapKeys[K comparable, V any](m map[K]V) Seq[K] {
return Seq[K](maps.Keys(m))
}
@@ -1030,3 +1042,78 @@ func MapToSeq2Value[T any, K comparable, V any](in Seq[T], mapFn func(ele T) (K,
}
}
}
+
+// First returns the first element in the sequence.
+// If the sequence is empty, the zero value of T is returned.
+// Example:
+//
+// seq := FromSlice([]int{1, 2, 3})
+// first, ok := First(seq)
+// // first is 1, ok is true
+func First[T any](in Seq[T]) (T, bool) {
+ var v T
+ var ok = false
+ for t := range in {
+ v = t
+ ok = true
+ break
+ }
+ return v, ok
+}
+
+// FirstO returns the first element in the sequence as an optional.O[T].
+// If the sequence is empty, the zero value of T is returned.
+// Example:
+//
+// seq := FromSlice([]int{1, 2, 3})
+// first, ok := FirstO(seq)
+// // first is 1, ok is true
+func FirstO[T any](in Seq[T]) optional.O[T] {
+ return optional.FromValue2(First(in))
+}
+
+// Last returns the last element in the sequence.
+// If the sequence is empty, the zero value of T is returned.
+// Example:
+//
+// seq := FromSlice([]int{1, 2, 3})
+// last, ok := Last(seq)
+// // last is 3, ok is true
+func Last[T any](in Seq[T]) (T, bool) {
+ var v T
+ var ok = false
+ for t := range in {
+ v = t
+ ok = true
+ }
+ return v, ok
+}
+
+// LastO returns the last element in the sequence as an optional.O[T].
+// If the sequence is empty, the zero value of T is returned.
+// Example:
+//
+// seq := FromSlice([]int{1, 2, 3})
+// last, ok := LastO(seq)
+// // last is 3, ok is true
+func LastO[T any](in Seq[T]) optional.O[T] {
+ return optional.FromValue2(Last(in))
+}
+
+// Compact returns a new sequence with the zero elements removed.
+//
+// EXAMPLE:
+//
+// Compact([]int{0, 1, 2, 3, 4}) 👉 [1 2 3 4]
+func Compact[T comparable](in Seq[T]) Seq[T] {
+ return func(yield func(T) bool) {
+ for t := range in {
+ if utils.IsZero(t) {
+ continue
+ }
+ if !yield(t) {
+ break
+ }
+ }
+ }
+}
diff --git a/pkg/xiter/xiter_common.go b/pkg/xiter/xiter_common.go
index 7a3b2b3..2fd3c4f 100644
--- a/pkg/xiter/xiter_common.go
+++ b/pkg/xiter/xiter_common.go
@@ -1,6 +1,7 @@
package xiter
import (
+ "github.com/dashjay/xiter/pkg/internal/constraints"
gassert "github.com/dashjay/xiter/pkg/internal/xassert"
"github.com/dashjay/xiter/pkg/optional"
)
@@ -111,3 +112,129 @@ func FromChan[T any](in <-chan T) Seq[T] {
}
}
}
+
+// Difference returns two sequences: the first sequence contains elements that are in the left sequence but not in the right sequence,
+// and the second sequence contains elements that are in the right sequence but not in the left sequence.
+//
+// EXAMPLE:
+//
+// left := []int{1, 2, 3, 4}
+// right := []int{3, 4, 5, 6}
+// onlyLeft, onlyRight := Difference(FromSlice(left), FromSlice(right))
+// // onlyLeft 👉 [1 2]
+// // onlyRight 👉 [5 6]
+func Difference[T comparable](left Seq[T], right Seq[T]) (onlyLeft Seq[T], onlyRight Seq[T]) {
+ leftMap := ToMapFromSeq(left, func(k T) struct{} {
+ return struct{}{}
+ })
+ rightMap := ToMapFromSeq(right, func(k T) struct{} {
+ return struct{}{}
+ })
+
+ return Filter(func(v T) bool {
+ _, ok := rightMap[v]
+ return !ok
+ }, left),
+ Filter(func(v T) bool {
+ _, ok := leftMap[v]
+ return !ok
+ }, right)
+}
+
+// Intersect return a seq that only contain elements in both left and right.
+//
+// EXAMPLE:
+//
+// left := []int{1, 2, 3, 4}
+// right := []int{3, 4, 5, 6}
+// intersect := Intersect(FromSlice(left), FromSlice(right))
+// // intersect 👉 [3 4]
+func Intersect[T comparable](left Seq[T], right Seq[T]) Seq[T] {
+ leftMap := ToMapFromSeq(left, func(k T) struct{} {
+ return struct{}{}
+ })
+ return Filter(func(v T) bool {
+ _, exists := leftMap[v]
+ return exists
+ }, right)
+}
+
+// Union return a seq that contain all elements in left and right.
+//
+// EXAMPLE:
+//
+// left := []int{1, 2, 3, 4}
+// right := []int{3, 4, 5, 6}
+// union := Union(FromSlice(left), FromSlice(right))
+// // union 👉 [1 2 3 4 5 6]
+func Union[T comparable](left, right Seq[T]) Seq[T] {
+ leftMap := ToMapFromSeq(left, func(k T) struct{} {
+ return struct{}{}
+ })
+ return Concat(left, Filter(func(v T) bool {
+ _, exists := leftMap[v]
+ return !exists
+ }, right))
+}
+
+// Mean return the mean of seq.
+//
+// EXAMPLE:
+//
+// mean := Mean(FromSlice([]int{1, 2, 3, 4, 5}))
+// // mean 👉 3
+func Mean[T constraints.Number](in Seq[T]) T {
+ var count T = 0
+ s := Reduce(func(sum T, v T) T {
+ count++
+ return sum + v
+ }, 0, in)
+ return s / count
+}
+
+// MeanBy return the mean of seq by fn.
+//
+// EXAMPLE:
+//
+// mean := MeanBy(FromSlice([]int{1, 2, 3, 4, 5}), func(v int) int {
+// return v * 2
+// })
+// // mean 👉 6
+func MeanBy[T any, R constraints.Number](in Seq[T], fn func(T) R) R {
+ var count R = 0
+ s := Reduce(func(sum R, v T) R {
+ count++
+ return sum + fn(v)
+ }, 0, in)
+ return s / count
+}
+
+// Moderate return the most common element in seq.
+//
+// EXAMPLE:
+//
+// moderate := Moderate(FromSlice([]int{1, 2, 3, 4, 5, 5, 5, 6, 6, 6, 6}))
+// // moderate 👉 6
+func Moderate[T comparable](in Seq[T]) (T, bool) {
+ var maxTimes int
+ var result T
+ _ = Reduce(func(sum map[T]int, v T) map[T]int {
+ sum[v]++
+ if sum[v] > maxTimes {
+ maxTimes = sum[v]
+ result = v
+ }
+ return sum
+ }, make(map[T]int), in)
+ return result, maxTimes > 0
+}
+
+// ModerateO return the most common element in seq.
+//
+// EXAMPLE:
+//
+// moderate := ModerateO(FromSlice([]int{1, 2, 3, 4, 5, 5, 5, 6, 6, 6, 6}))
+// // moderate 👉 6
+func ModerateO[T constraints.Number](in Seq[T]) optional.O[T] {
+ return optional.FromValue2(Moderate(in))
+}
diff --git a/pkg/xiter/xiter_common_test.go b/pkg/xiter/xiter_common_test.go
index 24eab63..6c367ff 100644
--- a/pkg/xiter/xiter_common_test.go
+++ b/pkg/xiter/xiter_common_test.go
@@ -1,9 +1,12 @@
package xiter_test
import (
+ "sort"
+ "strconv"
+ "testing"
+
"github.com/dashjay/xiter/pkg/xiter"
"github.com/stretchr/testify/assert"
- "testing"
)
func TestXIterCommon(t *testing.T) {
@@ -72,4 +75,57 @@ func TestXIterCommon(t *testing.T) {
seq := xiter.FromChan(ch)
testLimit(t, seq, 1)
})
+
+ t.Run("difference", func(t *testing.T) {
+ left := xiter.FromSlice(_range(0, 10))
+ right := xiter.FromSlice(_range(5, 15))
+ onlyLeft, onlyRight := xiter.Difference(left, right)
+ assert.Equal(t, _range(0, 5), xiter.ToSlice(onlyLeft))
+ assert.Equal(t, _range(10, 15), xiter.ToSlice(onlyRight))
+ })
+
+ t.Run("intersect", func(t *testing.T) {
+ left := xiter.FromSlice(_range(0, 10))
+ right := xiter.FromSlice(_range(5, 15))
+ assert.Equal(t, _range(5, 10), xiter.ToSlice(xiter.Intersect(left, right)))
+ assert.True(t, xiter.Equal(left, xiter.Intersect(left, left)))
+ })
+
+ t.Run("mean", func(t *testing.T) {
+ // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
+ seq := xiter.FromSlice(_range(0, 10))
+ r := xiter.Mean(seq)
+ assert.Equal(t, xiter.Sum(seq)/len(_range(0, 10)), r)
+ })
+
+ t.Run("mean by", func(t *testing.T) {
+ strSeq := xiter.Map(func(in int) string {
+ return strconv.Itoa(in)
+ }, xiter.FromSlice(_range(0, 10)))
+
+ r := xiter.MeanBy(strSeq, func(t string) int {
+ v, _ := strconv.Atoi(t)
+ return v
+ })
+ assert.Equal(t, xiter.Sum(xiter.FromSlice(_range(0, 10)))/len(_range(0, 10)), r)
+ })
+ t.Run("moderate", func(t *testing.T) {
+ moderate := xiter.ModerateO(xiter.FromSlice([]int{1, 2, 3, 4, 5, 5, 5, 6, 6, 6, 6}))
+ assert.True(t, moderate.Ok())
+ assert.Equal(t, 6, moderate.Must())
+ })
+
+ t.Run("union", func(t *testing.T) {
+ left := xiter.FromSlice(_range(0, 10))
+ right := xiter.FromSlice(_range(5, 15))
+ x := xiter.ToSlice(xiter.Union(left, right))
+ sort.Sort(sort.IntSlice(x))
+ assert.Equal(t, _range(0, 15), x)
+
+ ut := func(int) struct{} {
+ return struct{}{}
+ }
+ assert.Equal(t, xiter.ToMapFromSeq(xiter.Union(left, right), ut),
+ xiter.ToMapFromSeq(xiter.Union(right, left), ut))
+ })
}
diff --git a/pkg/xiter/xiter_old.go b/pkg/xiter/xiter_old.go
index bb5866d..1f5a114 100644
--- a/pkg/xiter/xiter_old.go
+++ b/pkg/xiter/xiter_old.go
@@ -11,6 +11,7 @@ import (
"github.com/dashjay/xiter/pkg/cmp"
"github.com/dashjay/xiter/pkg/internal/constraints"
+ "github.com/dashjay/xiter/pkg/internal/utils"
"github.com/dashjay/xiter/pkg/optional"
"github.com/dashjay/xiter/pkg/union"
)
@@ -348,6 +349,15 @@ func ToMap[K comparable, V any](seq Seq2[K, V]) (out map[K]V) {
return out
}
+func ToMapFromSeq[K comparable, V any](seq Seq[K], fn func(k K) V) (out map[K]V) {
+ out = make(map[K]V)
+ seq(func(k K) bool {
+ out[k] = fn(k)
+ return true
+ })
+ return out
+}
+
func FromMapKeys[K comparable, V any](m map[K]V) Seq[K] {
return func(yield func(K) bool) {
for k := range m {
@@ -931,3 +941,44 @@ func MapToSeq2Value[T any, K comparable, V any](in Seq[T], mapFn func(T) (K, V))
})
}
}
+
+func First[T any](in Seq[T]) (T, bool) {
+ var v T
+ var ok = false
+ in(func(t T) bool {
+ v = t
+ ok = true
+ return false
+ })
+ return v, ok
+}
+
+func FirstO[T any](in Seq[T]) optional.O[T] {
+ return optional.FromValue2(First(in))
+}
+
+func Last[T any](in Seq[T]) (T, bool) {
+ var v T
+ var ok = false
+ in(func(t T) bool {
+ v = t
+ ok = true
+ return true
+ })
+ return v, ok
+}
+
+func LastO[T any](in Seq[T]) optional.O[T] {
+ return optional.FromValue2(Last(in))
+}
+
+func Compact[T comparable](in Seq[T]) Seq[T] {
+ return func(yield func(T) bool) {
+ in(func(t T) bool {
+ if utils.IsZero(t) {
+ return true
+ }
+ return yield(t)
+ })
+ }
+}
diff --git a/pkg/xiter/xiter_test.go b/pkg/xiter/xiter_test.go
index f83deb3..63c4cec 100644
--- a/pkg/xiter/xiter_test.go
+++ b/pkg/xiter/xiter_test.go
@@ -391,6 +391,34 @@ func TestXIter(t *testing.T) {
testLimit2(t, seq2, 1)
assert.Equal(t, 9, xiter.ToMap(seq2)["3"])
})
+
+ t.Run("first", func(t *testing.T) {
+ val, ok := xiter.First(xiter.FromSlice([]int{0, 1, 2, 3, 4}))
+ assert.True(t, ok)
+ assert.Equal(t, 0, val)
+ assert.Equal(t, 0, xiter.FirstO(xiter.FromSlice([]int{0, 1, 2, 3, 4})).Must())
+
+ val, ok = xiter.First(xiter.FromSlice([]int{}))
+ assert.False(t, ok)
+ assert.False(t, xiter.FirstO(xiter.FromSlice([]int{})).Ok())
+ })
+
+ t.Run("last", func(t *testing.T) {
+ val, ok := xiter.Last(xiter.FromSlice([]int{0, 1, 2, 3, 4}))
+ assert.True(t, ok)
+ assert.Equal(t, 4, val)
+ assert.Equal(t, 4, xiter.LastO(xiter.FromSlice([]int{0, 1, 2, 3, 4})).Must())
+
+ val, ok = xiter.Last(xiter.FromSlice([]int{}))
+ assert.False(t, ok)
+ assert.False(t, xiter.LastO(xiter.FromSlice([]int{})).Ok())
+ })
+
+ t.Run("compact", func(t *testing.T) {
+ seq := xiter.Compact(xiter.FromSlice([]int{0, 1, 2, 3, 4}))
+ testLimit(t, seq, 1)
+ assert.Equal(t, []int{1, 2, 3, 4}, xiter.ToSlice(seq))
+ })
}
func TestXIter61898(t *testing.T) {
diff --git a/pkg/xslice/README.md b/pkg/xslice/README.md
index 6d8b8ed..07395fc 100644
--- a/pkg/xslice/README.md
+++ b/pkg/xslice/README.md
@@ -17,15 +17,19 @@ import "github.com/dashjay/xiter/pkg/xslice"
- [func ChunkInPlace\[T any, Slice \~\[\]T\]\(in Slice, chunkSize int\) \[\]Slice](<#ChunkInPlace>)
- [func Clone\[T any\]\(in \[\]T\) \[\]T](<#Clone>)
- [func CloneBy\[T any, U any\]\(in \[\]T, f func\(T\) U\) \[\]U](<#CloneBy>)
+- [func Compact\[T comparable, Slice \~\[\]T\]\(in Slice\) Slice](<#Compact>)
- [func Concat\[T any\]\(vs ...\[\]T\) \[\]T](<#Concat>)
- [func Contains\[T comparable\]\(in \[\]T, v T\) bool](<#Contains>)
- [func ContainsAll\[T comparable\]\(in \[\]T, v \[\]T\) bool](<#ContainsAll>)
- [func ContainsAny\[T comparable\]\(in \[\]T, v \[\]T\) bool](<#ContainsAny>)
- [func ContainsBy\[T any\]\(in \[\]T, f func\(T\) bool\) bool](<#ContainsBy>)
- [func Count\[T any\]\(in \[\]T\) int](<#Count>)
+- [func Difference\[T comparable, Slice \~\[\]T\]\(left, right Slice\) \(onlyLeft, onlyRight Slice\)](<#Difference>)
- [func Filter\[T any, Slice \~\[\]T\]\(in Slice, f func\(T\) bool\) Slice](<#Filter>)
- [func Find\[T any\]\(in \[\]T, f func\(T\) bool\) \(val T, found bool\)](<#Find>)
- [func FindO\[T any\]\(in \[\]T, f func\(T\) bool\) optional.O\[T\]](<#FindO>)
+- [func First\[T any, Slice \~\[\]T\]\(in Slice\) \(T, bool\)](<#First>)
+- [func FirstO\[T any, Slice \~\[\]T\]\(in Slice\) optional.O\[T\]](<#FirstO>)
- [func ForEach\[T any\]\(in \[\]T, f func\(T\) bool\)](<#ForEach>)
- [func ForEachIdx\[T any\]\(in \[\]T, f func\(idx int, v T\) bool\)](<#ForEachIdx>)
- [func GroupBy\[T any, K comparable, Slice \~\[\]T\]\(in Slice, f func\(T\) K\) map\[K\]Slice](<#GroupBy>)
@@ -33,7 +37,10 @@ import "github.com/dashjay/xiter/pkg/xslice"
- [func Head\[T any\]\(in \[\]T\) \(v T, hasOne bool\)](<#Head>)
- [func HeadO\[T any\]\(in \[\]T\) optional.O\[T\]](<#HeadO>)
- [func Index\[T comparable, Slice \~\[\]T\]\(in Slice, v T\) int](<#Index>)
+- [func Intersect\[T comparable, Slice \~\[\]T\]\(left, right Slice\) Slice](<#Intersect>)
- [func Join\[T \~string\]\(in \[\]T, sep T\) T](<#Join>)
+- [func Last\[T any, Slice \~\[\]T\]\(in Slice\) \(T, bool\)](<#Last>)
+- [func LastO\[T any, Slice \~\[\]T\]\(in Slice\) optional.O\[T\]](<#LastO>)
- [func Map\[T any, U any\]\(in \[\]T, f func\(T\) U\) \[\]U](<#Map>)
- [func Max\[T constraints.Ordered\]\(in \[\]T\) optional.O\[T\]](<#Max>)
- [func MaxBy\[T constraints.Ordered\]\(in \[\]T, f func\(T, T\) bool\) optional.O\[T\]](<#MaxBy>)
@@ -54,6 +61,7 @@ import "github.com/dashjay/xiter/pkg/xslice"
- [func Sum\[T constraints.Number, Slice \~\[\]T\]\(in Slice\) T](<#Sum>)
- [func SumBy\[T any, R constraints.Number, Slice \~\[\]T\]\(in Slice, f func\(T\) R\) R](<#SumBy>)
- [func SumN\[T constraints.Number\]\(in ...T\) T](<#SumN>)
+- [func Union\[T comparable, Slice \~\[\]T\]\(left, right Slice\) Slice](<#Union>)
- [func Uniq\[T comparable, Slice \~\[\]T\]\(in Slice\) Slice](<#Uniq>)
@@ -140,7 +148,7 @@ xslice.AvgN() 👉 float(0)
```
-## func [Chunk]()
+## func [Chunk]()
```go
func Chunk[T any, Slice ~[]T](in Slice, chunkSize int) []Slice
@@ -157,7 +165,7 @@ xslice.Chunk([]int{1, 2, 3, 4, 5}, 0) 👉 []int{}
```
-## func [ChunkInPlace]()
+## func [ChunkInPlace]()
```go
func ChunkInPlace[T any, Slice ~[]T](in Slice, chunkSize int) []Slice
@@ -172,7 +180,7 @@ xslice.Chunk([]int{1, 2, 3, 4, 5}, 0) 👉 []int{}
```
-## func [Clone]()
+## func [Clone]()
```go
func Clone[T any](in []T) []T
@@ -187,7 +195,7 @@ xslice.Clone([]int{1, 2, 3}) 👉 [1, 2, 3]
```
-## func [CloneBy]()
+## func [CloneBy]()
```go
func CloneBy[T any, U any](in []T, f func(T) U) []U
@@ -202,8 +210,23 @@ xslice.CloneBy([]int{1, 2, 3}, func(x int) int { return x * 2 }) 👉 [2, 4, 6]
xslice.CloneBy([]int{1, 2, 3}, strconv.Itoa) 👉 ["1", "2", "3"]
```
+
+## func [Compact]()
+
+```go
+func Compact[T comparable, Slice ~[]T](in Slice) Slice
+```
+
+Compact returns a new slice with the zero elements removed.
+
+EXAMPLE:
+
+```
+xslice.Compact([]int{0, 1, 2, 3, 4}) 👉 [1 2 3 4]
+```
+
-## func [Concat]()
+## func [Concat]()
```go
func Concat[T any](vs ...[]T) []T
@@ -307,8 +330,27 @@ xslice.Count([]int{1, 2, 3}) 👉 3
xslice.Count([]int{}) 👉 0
```
+
+## func [Difference]()
+
+```go
+func Difference[T comparable, Slice ~[]T](left, right Slice) (onlyLeft, onlyRight Slice)
+```
+
+Difference returns two slices: the first slice contains the elements that are in the left slice but not in the right slice, and the second slice contains the elements that are in the right slice but not in the left slice.
+
+EXAMPLE:
+
+```
+left := []int{1, 2, 3, 4, 5}
+right := []int{4, 5, 6, 7, 8}
+onlyLeft, onlyRight := xslice.Difference(left, right)
+fmt.Println(onlyLeft) // [1 2 3]
+fmt.Println(onlyRight) // [6 7 8]
+```
+
-## func [Filter]()
+## func [Filter]()
```go
func Filter[T any, Slice ~[]T](in Slice, f func(T) bool) Slice
@@ -354,6 +396,34 @@ xslice.FindO(_range(0, 10), func(x int) bool { return x == 1 }).Must() 👉 1
xslice.FindO(_range(0, 10), func(x int) bool { return x == -1 }).Ok() 👉 false
```
+
+## func [First]()
+
+```go
+func First[T any, Slice ~[]T](in Slice) (T, bool)
+```
+
+First returns the first element in the slice. If the slice is empty, the zero value of T is returned. EXAMPLE:
+
+```
+xslice.First([]int{1, 2, 3}) 👉 1
+xslice.First([]int{}) 👉 0
+```
+
+
+## func [FirstO]()
+
+```go
+func FirstO[T any, Slice ~[]T](in Slice) optional.O[T]
+```
+
+FirstO returns the first element in the slice as an optional.O\[T\]. If the slice is empty, the zero value of T is returned. EXAMPLE:
+
+```
+xslice.FirstO([]int{1, 2, 3}) 👉 1
+xslice.FirstO([]int{}) 👉 0
+```
+
## func [ForEach]()
@@ -399,7 +469,7 @@ Output:
```
-## func [GroupBy]()
+## func [GroupBy]()
```go
func GroupBy[T any, K comparable, Slice ~[]T](in Slice, f func(T) K) map[K]Slice
@@ -414,7 +484,7 @@ xslice.GroupBy([]int{1, 2, 3, 2, 4}, func(x int) int { return x % 2 }) 👉 map[
```
-## func [GroupByMap]()
+## func [GroupByMap]()
```go
func GroupByMap[T any, Slice ~[]T, K comparable, V any](in Slice, f func(T) (K, V)) map[K][]V
@@ -461,7 +531,7 @@ xslice.HeadO(_range(0, 0)).Ok() 👉 false
```
-## func [Index]()
+## func [Index]()
```go
func Index[T comparable, Slice ~[]T](in Slice, v T) int
@@ -475,6 +545,24 @@ xslice.Index([]int{1, 2, 3, 4, 5}, 3) 👉 2
xslice.Index([]int{1, 2, 3, 4, 5}, 666) 👉 -1
```
+
+## func [Intersect]()
+
+```go
+func Intersect[T comparable, Slice ~[]T](left, right Slice) Slice
+```
+
+Intersect returns a slice that contains the elements that are in both left and right slices.
+
+EXAMPLE:
+
+```
+left := []int{1, 2, 3, 4, 5}
+right := []int{4, 5, 6, 7, 8}
+intersect := xslice.Intersect(left, right)
+fmt.Println(intersect) // [4 5]
+```
+
## func [Join]()
@@ -491,6 +579,34 @@ xslice.Join([]string{"1", "2", "3"}, ".") 👉 "1.2.3"
xslice.Join([]string{}, ".") 👉 ""
```
+
+## func [Last]()
+
+```go
+func Last[T any, Slice ~[]T](in Slice) (T, bool)
+```
+
+Last returns the last element in the slice. If the slice is empty, the zero value of T is returned. EXAMPLE:
+
+```
+xslice.Last([]int{1, 2, 3}) 👉 3
+xslice.Last([]int{}) 👉 0
+```
+
+
+## func [LastO]()
+
+```go
+func LastO[T any, Slice ~[]T](in Slice) optional.O[T]
+```
+
+LastO returns the last element in the slice as an optional.O\[T\]. If the slice is empty, the zero value of T is returned. EXAMPLE:
+
+```
+xslice.LastO([]int{1, 2, 3}) 👉 3
+xslice.LastO([]int{}) 👉 0
+```
+
## func [Map]()
@@ -600,7 +716,7 @@ xslice.MinN(1, 2, 3) 👉 1
```
-## func [Repeat]()
+## func [Repeat]()
```go
func Repeat[T any, Slice ~[]T](in Slice, count int) Slice
@@ -616,7 +732,7 @@ xslice.Repeat([]int{1, 2, 3}, 0) 👉 []int{}
```
-## func [RepeatBy]()
+## func [RepeatBy]()
```go
func RepeatBy[T any](n int, f func(i int) T) []T
@@ -632,7 +748,7 @@ xslice.RepeatBy(3, func(i int) string { return strconv.Itoa(i) }) 👉 []string{
```
-## func [Replace]()
+## func [Replace]()
```go
func Replace[T comparable, Slice ~[]T](in Slice, from, to T, count int) []T
@@ -648,7 +764,7 @@ xslice.Replace([]int{1, 2, 2}, 2, 4, -1) 👉 [1, 4, 4]
```
-## func [ReplaceAll]()
+## func [ReplaceAll]()
```go
func ReplaceAll[T comparable, Slice ~[]T](in Slice, from, to T) []T
@@ -664,7 +780,7 @@ xslice.ReplaceAll([]int{1, 2, 2}, 2, 4) 👉 [1, 4, 4]
```
-## func [Reverse]()
+## func [Reverse]()
```go
func Reverse[T any, Slice ~[]T](in Slice)
@@ -680,7 +796,7 @@ xslice.Reverse([]int{}) 👉 []int{}
```
-## func [ReverseClone]()
+## func [ReverseClone]()
```go
func ReverseClone[T any, Slice ~[]T](in Slice) Slice
@@ -697,7 +813,7 @@ xslice.ReverseClone([]int{3, 2, 1}) 👉 [1, 2, 3]
```
-## func [Shuffle]()
+## func [Shuffle]()
```go
func Shuffle[T any, Slice ~[]T](in Slice) Slice
@@ -713,7 +829,7 @@ xslice.Shuffle([]int{}) 👉 []int{}
```
-## func [ShuffleInPlace]()
+## func [ShuffleInPlace]()
```go
func ShuffleInPlace[T any, Slice ~[]T](in Slice)
@@ -729,7 +845,7 @@ xslice.ShuffleInPlace(array) 👉 [2, 1, 3] (random)
```
-## func [Subset]()
+## func [Subset]()
```go
func Subset[T any, Slice ~[]T](in Slice, start, count int) Slice
@@ -745,7 +861,7 @@ xslice.Subset([]int{1, 2, 3}, -1, 2) 👉 [2, 3]
```
-## func [SubsetInPlace]()
+## func [SubsetInPlace]()
```go
func SubsetInPlace[T any, Slice ~[]T](in Slice, start int, count int) Slice
@@ -759,7 +875,7 @@ xslice.SubsetInPlace([]int{1, 2, 3}, -1, 2) 👉 [2, 3]
```
-## func [Sum]()
+## func [Sum]()
```go
func Sum[T constraints.Number, Slice ~[]T](in Slice) T
@@ -775,7 +891,7 @@ xslice.Sum([]int{}) 👉 0
```
-## func [SumBy]()
+## func [SumBy]()
```go
func SumBy[T any, R constraints.Number, Slice ~[]T](in Slice, f func(T) R) R
@@ -794,7 +910,7 @@ xslice.SumBy([]string{}, func(x string) int { return 0 }) 👉 0
```
-## func [SumN]()
+## func [SumN]()
```go
func SumN[T constraints.Number](in ...T) T
@@ -809,8 +925,26 @@ xslice.SumN(1, 2, 3) 👉 6
xslice.SumN() 👉 0
```
+
+## func [Union]()
+
+```go
+func Union[T comparable, Slice ~[]T](left, right Slice) Slice
+```
+
+Union returns a slice that contains all elements in left and right slices.
+
+EXAMPLE:
+
+```
+left := []int{1, 2, 3, 4}
+right := []int{3, 4, 5, 6}
+union := xslice.Union(left, right)
+fmt.Println(union) // [1 2 3 4 5 6]
+```
+
-## func [Uniq]()
+## func [Uniq]()
```go
func Uniq[T comparable, Slice ~[]T](in Slice) Slice
diff --git a/pkg/xslice/xslice.go b/pkg/xslice/xslice.go
index 5a321c4..6644b18 100644
--- a/pkg/xslice/xslice.go
+++ b/pkg/xslice/xslice.go
@@ -267,11 +267,7 @@ func MaxBy[T constraints.Ordered](in []T, f func(T, T) bool) optional.O[T] {
// xslice.Map([]int{1, 2, 3}, func(x int) int { return x * 2 }) 👉 [2, 4, 6]
// xslice.Map([]int{1, 2, 3}, strconv.Itoa) 👉 ["1", "2", "3"]
func Map[T any, U any](in []T, f func(T) U) []U {
- out := make([]U, len(in))
- for i := range in {
- out[i] = f(in[i])
- }
- return out
+ return xiter.ToSlice(xiter.Map(f, xiter.FromSlice(in)))
}
// Clone returns a copy of the slice.
@@ -580,3 +576,103 @@ func GroupByMap[T any, Slice ~[]T, K comparable, V any](in Slice, f func(T) (K,
func Filter[T any, Slice ~[]T](in Slice, f func(T) bool) Slice {
return xiter.ToSlice(xiter.Filter(f, xiter.FromSlice(in)))
}
+
+// Compact returns a new slice with the zero elements removed.
+//
+// EXAMPLE:
+//
+// xslice.Compact([]int{0, 1, 2, 3, 4}) 👉 [1 2 3 4]
+func Compact[T comparable, Slice ~[]T](in Slice) Slice {
+ return xiter.ToSlice(xiter.Compact(xiter.FromSlice(in)))
+}
+
+// First returns the first element in the slice.
+// If the slice is empty, the zero value of T is returned.
+// EXAMPLE:
+//
+// xslice.First([]int{1, 2, 3}) 👉 1
+// xslice.First([]int{}) 👉 0
+func First[T any, Slice ~[]T](in Slice) (T, bool) {
+ return xiter.First(xiter.FromSlice(in))
+}
+
+// FirstO returns the first element in the slice as an optional.O[T].
+// If the slice is empty, the zero value of T is returned.
+// EXAMPLE:
+//
+// xslice.FirstO([]int{1, 2, 3}) 👉 1
+// xslice.FirstO([]int{}) 👉 0
+func FirstO[T any, Slice ~[]T](in Slice) optional.O[T] {
+ return optional.FromValue2(First(in))
+}
+
+// Last returns the last element in the slice.
+// If the slice is empty, the zero value of T is returned.
+// EXAMPLE:
+//
+// xslice.Last([]int{1, 2, 3}) 👉 3
+// xslice.Last([]int{}) 👉 0
+func Last[T any, Slice ~[]T](in Slice) (T, bool) {
+ return xiter.Last(xiter.FromSlice(in))
+}
+
+// LastO returns the last element in the slice as an optional.O[T].
+// If the slice is empty, the zero value of T is returned.
+// EXAMPLE:
+//
+// xslice.LastO([]int{1, 2, 3}) 👉 3
+// xslice.LastO([]int{}) 👉 0
+func LastO[T any, Slice ~[]T](in Slice) optional.O[T] {
+ return optional.FromValue2(Last(in))
+}
+
+// Difference returns two slices: the first slice contains the elements that are in the left slice but not in the right slice,
+// and the second slice contains the elements that are in the right slice but not in the left slice.
+//
+// EXAMPLE:
+//
+// left := []int{1, 2, 3, 4, 5}
+// right := []int{4, 5, 6, 7, 8}
+// onlyLeft, onlyRight := xslice.Difference(left, right)
+// fmt.Println(onlyLeft) // [1 2 3]
+// fmt.Println(onlyRight) // [6 7 8]
+func Difference[T comparable, Slice ~[]T](left, right Slice) (onlyLeft, onlyRight Slice) {
+ onlyLeftSeq, onlyRightSeq := xiter.Difference(xiter.FromSlice(left), xiter.FromSlice(right))
+ return xiter.ToSlice(onlyLeftSeq), xiter.ToSlice(onlyRightSeq)
+}
+
+// Intersect returns a slice that contains the elements that are in both left and right slices.
+//
+// EXAMPLE:
+//
+// left := []int{1, 2, 3, 4, 5}
+// right := []int{4, 5, 6, 7, 8}
+// intersect := xslice.Intersect(left, right)
+// fmt.Println(intersect) // [4 5]
+func Intersect[T comparable, Slice ~[]T](left, right Slice) Slice {
+ var smaller, larger Slice
+ if len(left) > len(right) {
+ smaller, larger = right, left
+ } else {
+ smaller, larger = left, right
+ }
+ return xiter.ToSlice(xiter.Intersect(xiter.FromSlice(smaller), xiter.FromSlice(larger)))
+}
+
+// Union returns a slice that contains all elements in left and right slices.
+//
+// EXAMPLE:
+//
+// left := []int{1, 2, 3, 4}
+// right := []int{3, 4, 5, 6}
+// union := xslice.Union(left, right)
+// fmt.Println(union) // [1 2 3 4 5 6]
+func Union[T comparable, Slice ~[]T](left, right Slice) Slice {
+ var smaller, larger Slice
+ if len(left) <= len(right) {
+ smaller, larger = left, right
+ } else {
+ smaller, larger = right, left
+ }
+ return xiter.ToSlice(xiter.Union(xiter.FromSlice(smaller), xiter.FromSlice(larger)))
+}
diff --git a/pkg/xslice/xslice_benchmark_test.go b/pkg/xslice/xslice_benchmark_test.go
index 53b9505..ce85966 100644
--- a/pkg/xslice/xslice_benchmark_test.go
+++ b/pkg/xslice/xslice_benchmark_test.go
@@ -2,6 +2,7 @@ package xslice_test
import (
"bytes"
+ "fmt"
"testing"
"github.com/samber/lo"
@@ -167,6 +168,36 @@ func BenchmarkSlice(b *testing.B) {
}
})
})
+
+ b.Run("benchmark map", func(b *testing.B) {
+ arr := _range(0, 1000)
+
+ b.Run("xslice", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ xslice.Map(arr, func(x int) string { return fmt.Sprintf("%d", x) })
+ }
+ })
+ b.Run("lo", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ lo.Map(arr, func(x int, index int) string { return fmt.Sprintf("%d", x) })
+ }
+ })
+ })
+
+ b.Run("benchmark difference", func(b *testing.B) {
+ left := _range(0, 1000)
+ right := _range(500, 1500)
+ b.Run("xslice", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ xslice.Difference(left, right)
+ }
+ })
+ b.Run("lo", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ lo.Difference(left, right)
+ }
+ })
+ })
}
func BenchmarkChunk(b *testing.B) {
diff --git a/pkg/xslice/xslice_test.go b/pkg/xslice/xslice_test.go
index 28578c6..597b304 100644
--- a/pkg/xslice/xslice_test.go
+++ b/pkg/xslice/xslice_test.go
@@ -1,6 +1,7 @@
package xslice_test
import (
+ "sort"
"strconv"
"testing"
@@ -324,4 +325,43 @@ func TestSlices(t *testing.T) {
t.Run("filter", func(t *testing.T) {
assert.Equal(t, []int{2, 4}, xslice.Filter([]int{1, 2, 3, 4}, func(x int) bool { return x%2 == 0 }))
})
+
+ t.Run("compact", func(t *testing.T) {
+ assert.Equal(t, []int{1, 2, 3, 4}, xslice.Compact([]int{0, 1, 2, 3, 4}))
+ })
+
+ t.Run("first", func(t *testing.T) {
+ assert.Equal(t, 1, xslice.FirstO([]int{1, 2, 3}).Must())
+ assert.False(t, xslice.FirstO([]int{}).Ok())
+ })
+
+ t.Run("last", func(t *testing.T) {
+ assert.Equal(t, 3, xslice.LastO([]int{1, 2, 3}).Must())
+ assert.False(t, xslice.LastO([]int{}).Ok())
+ })
+
+ t.Run("difference", func(t *testing.T) {
+ left := []int{1, 2, 3, 4, 5}
+ right := []int{4, 5, 6, 7, 8}
+ onlyLeft, onlyRight := xslice.Difference(left, right)
+ assert.Equal(t, []int{1, 2, 3}, onlyLeft)
+ assert.Equal(t, []int{6, 7, 8}, onlyRight)
+ })
+
+ t.Run("intersect", func(t *testing.T) {
+ left := []int{1, 2, 3, 4, 5, 6}
+ right := []int{4, 5, 6, 7, 8}
+ assert.Equal(t, []int{4, 5, 6}, xslice.Intersect(left, right))
+ assert.Equal(t, []int{4, 5, 6}, xslice.Intersect(right, left))
+
+ assert.Equal(t, left, xslice.Intersect(left, left))
+ })
+
+ t.Run("union", func(t *testing.T) {
+ left := []int{1, 2, 3, 4, 5, 6}
+ right := []int{4, 5, 6, 7, 8}
+ res := xslice.Union(left, right)
+ sort.Sort(sort.IntSlice(res))
+ assert.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8}, res)
+ })
}
diff --git a/pkg/xstl/list/example_test.go b/pkg/xstl/list/example_test.go
index a2c8817..66fb62e 100644
--- a/pkg/xstl/list/example_test.go
+++ b/pkg/xstl/list/example_test.go
@@ -6,7 +6,7 @@ package list_test
import (
"fmt"
-
+
"github.com/dashjay/xiter/pkg/xstl/list"
)