Skip to content

Instantly share code, notes, and snippets.

@rstropek
Created June 9, 2022 12:36
Show Gist options
  • Save rstropek/9b78601f56c8990a127e002e488c06c7 to your computer and use it in GitHub Desktop.
Save rstropek/9b78601f56c8990a127e002e488c06c7 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"reflect"
"golang.org/x/exp/constraints"
)
type lentil struct {
isGood bool
}
func (l lentil) shouldEat() bool { return !l.isGood }
type snail struct {
hasHouse bool
}
func (s snail) shouldEat() bool { return !s.hasHouse }
type eatOrKeep interface {
shouldEat() bool
}
type bird struct{}
func (b bird) process(items []eatOrKeep) []eatOrKeep {
result := []eatOrKeep{}
for _, item := range items {
if !item.shouldEat() {
result = append(result, item)
}
}
return result
}
func processInterface(itemsSlice interface{}, filter interface{}) interface{} {
items := reflect.ValueOf(itemsSlice)
result := reflect.MakeSlice(items.Type(), 0, 0)
funcValue := reflect.ValueOf(filter)
for i := 0; i < items.Len(); i++ {
item := items.Index(i)
keep := funcValue.Call([]reflect.Value{item})[0].Bool()
if keep {
result = reflect.Append(result, item)
}
}
return result.Interface()
}
func process[I any](items []I, filter func(i I) bool) []I {
result := []I{}
for _, item := range items {
if filter(item) {
result = append(result, item)
}
}
return result
}
type itemGroup[T any] struct {
item T
count int
}
type itemsBag[T any] struct {
bag []itemGroup[T]
equalityComparer func(T, T) bool
}
func newItemsBag[T any](comparer func(T, T) bool) *itemsBag[T] {
return &itemsBag[T]{
bag: make([]itemGroup[T], 0),
equalityComparer: comparer,
}
}
func (b *itemsBag[T]) append(item T) {
if len(b.bag) == 0 || !b.equalityComparer(item, b.bag[len(b.bag)-1].item) {
b.bag = append(b.bag, itemGroup[T]{item: item, count: 1})
} else {
b.bag[len(b.bag)-1].count++
}
}
func (b itemsBag[T]) getItems() []T {
result := []T{}
for _, item := range b.bag {
for i := 0; i < item.count; i++ {
result = append(result, item.item)
}
}
return result
}
func processChannel[I any](items <-chan I, filter func(i I) bool) <-chan I {
out := make(chan I)
go func() {
defer close(out)
for item := range items {
if filter(item) {
out <- item
}
}
}()
return out
}
const (
SMALL = 1
MEDIUM = 2
LARGE = 3
)
// Lentil with size information
type sizedLentil struct {
lentil
lentilSize int
}
func (l sizedLentil) size() int { return l.lentilSize }
type sized interface {
size() int
}
// Define an interface that will be used as a type constraint
type sizedEatOrKeep interface {
sized
eatOrKeep
}
func processAndSort[I sizedEatOrKeep](items []I, filter func(i I) bool) []I {
result := []I{}
for _, item := range items {
if filter(item) {
result = append(result, item)
}
}
bubblesort(result, func(item I) int { return item.size() })
return result
}
func bubblesort[I any, O constraints.Ordered](items []I, toOrdered func(item I) O) {
for itemCount := len(items) - 1; ; itemCount-- {
hasChanged := false
for index := 0; index < itemCount; index++ {
// We use the provided function to turn each item into a type compatible
// with Ordered. With that, we can use comparison operators.
if toOrdered(items[index]) > toOrdered(items[index+1]) {
items[index], items[index+1] = items[index+1], items[index]
hasChanged = true
}
}
if !hasChanged {
break
}
}
}
func main() {
bag := newItemsBag(func(lhs eatOrKeep, rhs eatOrKeep) bool { return lhs.shouldEat() == rhs.shouldEat() })
bag.append(lentil{isGood: true})
bag.append(lentil{isGood: true})
bag.append(snail{hasHouse: false})
bag.append(snail{hasHouse: false})
processedItems := process(bag.getItems(), func(item eatOrKeep) bool { return !item.shouldEat() })
fmt.Println("Eaten:", 4-len(processedItems), "Kept:", len(processedItems))
in := make(chan eatOrKeep, 4)
in <- lentil{isGood: true}
in <- lentil{isGood: true}
in <- snail{hasHouse: false}
in <- snail{hasHouse: false}
close(in)
total := len(in)
remaining := 0
asyncProcessedItems := processChannel(in, func(item eatOrKeep) bool { return !item.shouldEat() })
for range asyncProcessedItems {
remaining++
}
fmt.Println("Eaten:", total-remaining, "Kept:", remaining)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment