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,reduceetc. 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
eachWhileimplementation 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) } }And the rest is done automatically:
holder := StrListHolder(["one", "two", "three", "four", "five"]) holder.each |Str s| { echo(s) } holder.eachr |Str s| { echo(s) } holder.find |Str s->Bool| { s.size == 5 } // "three" holder.findAll |Str s->Bool| { s.size == 3 } // [one, two] holder.reduce(StrBuf()) |StrBuf r, Str item -> Obj| { r.add(item) } //concat holder.map |Str s->Obj| { s.size } //[3, 3, 5, 4, 4]EDIT: corrected small error in
eachrWhileKevinKelley Tue 22 Dec 2009
Works for
anyandalltoo --Bool any(|Obj, Int->Bool| f) { eachWhile |v,i->Obj?| { if (f.call(v,i)) return true; return null } != null } Bool all(|Obj, Int->Bool| f) { !any |v,i->Bool| { !f.call(v,i) } }ivan Tue 22 Dec 2009
oh yes, forgot about any and all. My version of
anyandalllooks a bit different:Bool any(|Obj->Bool| f) { eachWhile { f(it) ? "" : null } != null } Bool all(|Obj->Bool| f) { eachWhile { f(it) ? null : "" } == null }KevinKelley Tue 22 Dec 2009
Yeah, those are prettier. :-) This is a pretty handy mixin to have around.