Sometimes I need common functions like each, eachr, reduce etc. in my classes which encapsulate lists. However writing all these methods (which just delegate to encapsulated list) is quite boring.
Then I noticed that it is enough to have only eachWhile implementation to write others (but not in most efficient way), so I wrote a simple mixin:
mixin Iterable
{
** Inheritors just need to implement this method
abstract Obj? eachWhile(|Obj->Obj?| f)
** Implementation based on `#eachWhile`
Void each(|Obj| f) { eachWhile |a| { f(a); return null } }
** Implementation based on `#each`
Obj? reduce(Obj? init, |Obj? r, Obj item->Obj?| f)
{
result := init
each |i| { result = f(result, i) }
return result
}
** inefficient, override if necessary
virtual Obj? eachrWhile(|Obj->Obj?| f)
{
stack := [,]; each |i| { stack.push(i) }
while(!stack.isEmpty) { fs := f(stack.pop); if(fs != null) return fs }
return null
}
Void eachr(|Obj| f) { eachrWhile |a| { f(a); return null } }
Obj find(|Obj->Bool| f) { eachWhile |i| { f(i) ? i : null } }
Obj[] findAll(|Obj->Bool| f) { reduce([,]) |Obj[] r, i| { f(i) ? r.add(i) : r } }
Obj[] map(|Obj->Obj?| f) { reduce([,]) |Obj?[] r, i| { r.add(f(i)) } }
}
Then, just implement eachWhile in my class:
class StrListHolder : Iterable
{
Str[] list
new make(Str[] list) { this.list = list }
override Obj? eachWhile(|Obj->Obj?| f) { list.eachWhile(f) }
}
ivan Tue 22 Dec 2009
Sometimes I need common functions like
each
,eachr
,reduce
etc. in my classes which encapsulate lists. However writing all these methods (which just delegate to encapsulated list) is quite boring.Then I noticed that it is enough to have only
eachWhile
implementation to write others (but not in most efficient way), so I wrote a simple mixin:Then, just implement eachWhile in my class:
And the rest is done automatically:
EDIT: corrected small error in
eachrWhile
KevinKelley Tue 22 Dec 2009
Works for
any
andall
too --ivan Tue 22 Dec 2009
oh yes, forgot about any and all. My version of
any
andall
looks a bit different:KevinKelley Tue 22 Dec 2009
Yeah, those are prettier. :-) This is a pretty handy mixin to have around.