Martin DeMello wrote:
> class Enumerable
> def build(seed)
> each {|i|
> seed.add(yield i)
> }
> end
> end
>
> and
>
> Array#build == Array#<<
> Hash#build(k,v) == Hash#
> etc
>
> So you could say [1,2,3].build({}) {|i| [i, 1]} for the question that
> prompted the to_hash thread, but also, in general, you can collect
> into non-array structures (binary trees, e.g.) as long as they
> implement a suitable #add method.
>
> (Of course, you can do ary.inject(seed) {|i| seed.add(f(i)); seed}
> right now but a #build method makes the common case pretty.)
Looks good. But,
- Enumerable is a module... 
- You should add seed as return value.
Oops - yes, I was enthused about the idea and got sloppy with the
actual code.
- Your first example won't work as Hash#add is nonexistent
No, that was my point - add a #add method (chosen not to conflict with
anything currently in the core) to any class that you wish to act as a
build "client".
An alternative approach would be to reverse the logic and have
Enumerable#populate:
module Enumerable
def populate(*enum)
enum = enum.first if enum.size == 1
enum.each {|*a| add(yield(*a))}
self
end
end
class Hash
def populate(*enum)
enum = enum.first if enum.size == 1
enum.each {|*a| send(:=, *yield(*a))}
self
end
end
>> h={}.populate(1,2,3) {|x| [x, "val #{x}"]}
=> {1=>"val 1", 2=>"val 2", 3=>"val 3"}
What do you think?
I'd make one change to your way - keep Addable separate from Enumerable.
Once we've done that, it's simple to add both #populate to Addable
(requires an Enumerable argument) and #build to Enumerable (regretting,
once again, that #collect is already a synonym of #map). One nice thing
is that classes implementing both Enumerable and Addable could then
provide a "structural map" - e.g.
class Hash
def smap
build({}) {|k,v| [k, yield(v)]}
end
end
{:x=>2, :y=>4}.smap {|i| i*i} #=> {:x => 4, :y => 16}
Or even something more complex like
class Tree
def each
...
yield [element, path]
end
def add args
element, path = args
...
end
def smap
build(Tree.new) {|e, path| [(yield e), path }
# or
# Tree.new.populate(self) {|e, path| [(yield e), path]}
end
end
martin
···
Robert Klemme <bob.news@gmx.net> wrote: