Repository: samber/lo
File: slice.go (Go)

Code before:
// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is
// invoked for each element in array to generate the criterion by which uniqueness is computed.
func UniqBy[T any, U comparable](collection []T, iteratee func(T) U) []T {
	result := make([]T, 0, len(collection))
	seen := make(map[U]struct{}, len(collection))

	for _, item := range collection {
		key := iteratee(item)

		if _, ok := seen[key]; ok {
			continue
		}

		seen[key] = struct{}{}
		result = append(result, item)
	}

	return result
}

// Duplicate returns a slice with the first occurence of each duplicated elements of the collection.
// The order of result values is determined by the order they occur in the collection.
func Duplicate[T comparable](collection []T) []T {
	isDupl := make(map[T]bool, len(collection))

	for _, item := range collection {
		duplicated, ok := isDupl[item]
		if !ok {
			isDupl[item] = false
		} else if !duplicated {
			isDupl[item] = true
		}
	}

	result := make([]T, 0, len(collection)-len(isDupl))

	for _, item := range collection {
		if duplicated := isDupl[item]; duplicated {
			result = append(result, item)
			isDupl[item] = false
		}
	}

	return result
}

// DuplicateBy returns a slice with the first occurence of each duplicated elements of the collection.
// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is
// invoked for each element in array to generate the criterion by which uniqueness is computed.
func DuplicateBy[T any, U comparable](collection []T, iteratee func(T) U) []T {
	isDupl := make(map[U]bool, len(collection))

Review comment (refactor):
You can do it in a single loop:

```go
for _, item := range collection {
    duplicated, ok := isDupl[item]
    if !ok {
	isDupl[item] = false
    } else if !duplicated {
	isDupl[item] = true
        result = append(result, item)
    }
}
```

Code after:
// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is
// invoked for each element in array to generate the criterion by which uniqueness is computed.
func UniqBy[T any, U comparable](collection []T, iteratee func(T) U) []T {
	result := make([]T, 0, len(collection))
	seen := make(map[U]struct{}, len(collection))

	for _, item := range collection {
		key := iteratee(item)

		if _, ok := seen[key]; ok {
			continue
		}

		seen[key] = struct{}{}
		result = append(result, item)
	}

	return result
}

// GroupBy returns an object composed of keys generated from the results of running each element of collection through iteratee.
func GroupBy[T any, U comparable](collection []T, iteratee func(T) U) map[U][]T {
	result := map[U][]T{}

	for _, item := range collection {
		key := iteratee(item)

		result[key] = append(result[key], item)
	}

	return result
}

// Chunk returns an array of elements split into groups the length of size. If array can't be split evenly,
// the final chunk will be the remaining elements.
func Chunk[T any](collection []T, size int) [][]T {
	if size <= 0 {
		panic("Second parameter must be greater than 0")
	}

	result := make([][]T, 0, len(collection)/2+1)
	length := len(collection)

	for i := 0; i < length; i++ {
		chunk := i / size

		if i%size == 0 {
			result = append(result, make([]T, 0, size))
		}

		result[chunk] = append(result[chunk], collection[i])