thoas / go-funk

A modern Go utility library which provides helpers (map, find, contains, filter, ...)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

funk.GroupBY

arshpreetsingh opened this issue · comments

Is there any way I can use funck.Groupby?

commented

There is no funk.GroupBy, you can implement it if you want and send me a PR.

@arshpreetsingh @thoas

I dont know if it is possible to re-open, or if you could make use of this directly.

groupBy is absolutely essential imo for this very fine library :D

Here is an idea of how it could be implemented (BIG WARNING: I started learning go 2 days ago so I am probably breaking every convention in the book!)

func GroupBy(list interface{}, pivotFunc interface{}) interface{} {

	if !funk.IsCollection(list) {
		panic(fmt.Sprintf("%v must be a collection (slice or array)", list))
	}

	// cheating here by using funk.Map, to get funk validation :).
	// Could have used reflect to call the pivot function, but then
	// I would need to re-implement all nice checks in go-funk
	keys := funk.Map(list, pivotFunc)
	count := reflect.ValueOf(keys).Len()

	keysR := reflect.ValueOf(keys)
	valuesR := reflect.ValueOf(list)

	valueType := valuesR.Type().Elem()
	keyType := reflect.TypeOf(pivotFunc).Out(0)

	sliceType := reflect.SliceOf(valueType)
	resultType := reflect.MapOf(keyType, sliceType)
	resultR := reflect.MakeMapWithSize(resultType, 0)

	initGroupCap := 1 + count/3
	if initGroupCap > 10 {
		initGroupCap = 10
	}

	for i := 0; i < count; i++ {

		keyR := keysR.Index(i)
		valueR := valuesR.Index(i)

		groupR := resultR.MapIndex(keyR)

		if groupR == (reflect.Value{}) {
			groupR = reflect.MakeSlice(sliceType, 0, initGroupCap)
		}

		newGroup := reflect.Append(groupR, valueR)
		resultR.SetMapIndex(keyR, newGroup)
	}

	return resultR.Interface()
}

}

With this, I can do the following

k8sResources := ... // []*kubectl.K8sResource

k8sResourcesByNamespace := coll.GroupBy(k8sResources, func(r *kubectl.K8sResource) string {
	return r.MetaData.Namespace
}).(map[string][]*kubectl.K8sResource)

for namespace, resources := range k8sResourcesByNamespace {
	....
	for _, resource := range resources {
		...

solved by #141