New method(?) collect_by

Hi, I have written a method collect_by.
I am not sure if it already exist, but it is very
usefull. It is a generic version of collect, that
works with any method. Basicly it converts the output
of any block to an Array

class Object
def collect_by(method, *args)
a = []
send(method, *args) { |*o|
a.push(block_given? ?
(yield *o) :
(o.size > 1 ? o : o[0])) }
return a
end
end

Examples:

“a string”.collect_by(:each_byte)
=> [97, 32, 115, 116, 114, 105, 110, 103]

3.collect_by(:step, 20, 4)
=>[3, 7, 11, 15, 19]

(3…7).collect_by(:each_with_index)
=> [[3, 0], [4, 1], [5, 2], [6, 3], [7, 4]]

5.collect_by(:times) { rand 100 }
=> [61, 85, 13, 52, 47]

5.collect_by(:times) { |i| i * i }
=> [0, 1, 4, 9, 16]

Interesting. I don’t think I’ve ever seen that before.

If you find that useful, perhaps you’ll find the following interesting:

class Object
def inject_by(init, method, *args, &blk)
a = init
send(method, *args) do |*o|
a = yield a, o
end
a
end

def collect_by(method, *args, &blk)
inject_by([], method, *args) do |a, o|
a << if blk
blk.call *o
else
o.size > 1 ? o : o[0]
end
end
end
end

My #collect_by and yours does the same thing, plus I made the even more
general #inject_by. :slight_smile:

I don’t know where I’d ever use this, but who knows?

Cheers.

  • Dan

Kristof Bastiaensen kristof@vleeuwen.org writes:

Hi, I have written a method collect_by.
I am not sure if it already exist, but it is very
usefull. It is a generic version of collect, that
works with any method. Basicly it converts the output
of any block to an Array

[…]

You might be interested in enumerator.rb in the std lib:

irb(main):001:0> require ‘enumerator’
=> true
irb(main):002:0> ‘a string’.enum_for(:each_byte).map{|x| x}
=> [97, 32, 115, 116, 114, 105, 110, 103]
irb(main):003:0> ‘a string’.enum_for(:each_byte).max
=> 116
irb(main):004:0> ‘a string’.enum_for(:each_byte).inject{|x,y| x+y}
=> 792

etc.

Hi,

yes that does exactly what I wanted. I knew it should exist,
but couldn’t find it.
I am still using ruby 1.6, so it must be part of 1.8.

Thanks,
Kristof

···

On Fri, 09 Apr 2004 05:03:18 +0200, George Ogata wrote:

You might be interested in enumerator.rb in the std lib:

irb(main):001:0> require ‘enumerator’ => true irb(main):002:0> ‘a
string’.enum_for(:each_byte).map{|x| x} => [97, 32, 115, 116, 114, 105,
110, 103] irb(main):003:0> ‘a string’.enum_for(:each_byte).max => 116
irb(main):004:0> ‘a string’.enum_for(:each_byte).inject{|x,y| x+y} =>
792

etc.

Hi,
I think it is very useful. I found out a general class is already
implemented in the std lib with enumerator. This way you
can use all the methods of Enumerator.
Some examples:

filling in an Array:

5.enum_for(:times).collect { Array.new(5) }
(maybe shorter: (0…4).collect { Array.new(5) }

string manipulation on bytes:

“a string”.enum_for(:each_byte).collect { |b| b + 3 }.join

Greetings,
Kristof

···

On Fri, 09 Apr 2004 04:01:39 +0200, Dan Doel wrote:

Interesting. I don’t think I’ve ever seen that before.

If you find that useful, perhaps you’ll find the following interesting:

class Object
def inject_by(init, method, *args, &blk)
a = init
send(method, *args) do |*o|
a = yield a, o
end
a
end

def collect_by(method, *args, &blk)
inject_by(, method, *args) do |a, o|
a << if blk
blk.call *o
else
o.size > 1 ? o : o[0]
end
end
end
end

My #collect_by and yours does the same thing, plus I made the even more
general #inject_by. :slight_smile:

I don’t know where I’d ever use this, but who knows?

Cheers.

  • Dan