reflect.Swapper の恩恵をうけたslice utility
Published on
標準のsort package では reflect.Swapper を利用した sort.Slice の 登場でだいぶ高速化された。
で自分でもslice を使って恩恵にあずかろうということで Select とかFilter とか Uniq みたいなもので具体的につくってみた (つくったのはちょっと前だが)
それが loncha ってやつです
linked-list もこのpackage に含まれているんだけど… go-funk がもってるようなものを高速化して実装してみたというかんじ
まず slice のデータ定義して
import "github.com/kazu/loncha"
type GameObject struct {
ID int
Name string
Pos []float
}
...
Find,Filder,Delete, Select, Shuffle とか
var objs []GameObject
loncha.Find(&objs, func(i int) bool {
return objs[i].ID == 6
}
loncha.Filter(&objs, func(i int) bool {
return objs[i].ID == 12
}
loncha.Delete(&objs, func(i int) bool {
return objs[i].ID == 555
})
// find one object with conditions.
obj, err := Select(&objs, func(i int) bool {
return slice[i].ID < 50
})
err = loncha.Shuffle(objs, 2)
sort.Slice と同じで 条件関数にinterface/reflect.ValueOf がからむと とたんに遅くなるので index だけ渡す感じにしてます。で中の処理は
movelist で移動するindex をいれておいて
movelist := make([]int, length)
... なんらかの処理
swap := reflect.Swapper(pRv.Elem().Interface())
for i, v := range movelist {
if v != -1 {
swap(i, v)
}
}
reflect.Swapper でslice の中身をバキュンて交換してます。
いちよ てで行った処理とgo-funk とloncha のベンチマークも軽くとってます
loncha.Uniq-16 1000 997543 ns/op 548480 B/op 16324 allocs/op
loncha.UniqWithSort-16 1000 2237924 ns/op 256 B/op 7 allocs/op
loncha.UniqWithSort(sort)-16 1000 260283 ns/op 144 B/op 4 allocs/op
hand_Uniq-16 1000 427765 ns/op 442642 B/op 8 allocs/op
hand_Uniq_iface-16 1000 808895 ns/op 632225 B/op 6322 allocs/op
go-funk.Uniq-16 1000 1708396 ns/op 655968 B/op 10004 allocs/op
pointer ってあるのは slice の要素をポインタにしたとき
loncha.Filter-16 100 89142 ns/op 82119 B/op 4 allocs/op
loncha.Filter_pointer-16 100 201 ns/op 0 B/op 0 allocs/op
hand_Filter_pointer-16 100 24432 ns/op 81921 B/op 1 allocs/op
go-funk.Filter-16 100 2370492 ns/op 640135 B/op 20004 allocs/op
go-funk.Filter_pointer-16 100 1048 ns/op 64 B/op 2 allocs/op
ポインタでも4倍ぐらいはやいが。実体だと条件関数に実体わたすのもあるし20倍以上ちがう
comments powered by Disqus