From: Harry Kakueki on
On Wed, Sep 2, 2009 at 1:41 AM, Max Williams<toastkid.williams(a)gmail.com> wrote:
>
>
> I have a situation where i have an array of 12 items. If someone
> chooses to have n of them (where n can be between 3 and 12) then i want
> to always include the first and last, and then 'spread' the others out
> as evenly as possible between the rest.
>
> So, lets say for the sake of argument that the array holds the numbers 1
> to 12.
>
>>> arr = (1..12).to_a
> => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>
> I would get results back like this
>
> arr.spread(3)
> => [1,6,12] (or [1,7,12], either is fine)
>
> arr.spread(4)
> => [1, 5, 9, 12] (or [1,4,8,12] or [1, 5, 8, 12])
>
>It feels like there should be a simple solution for this but i can't
>think of a nice way. Anyone?
>
>thanks
>max



Thanks to a post by David Masover in a recent thread, I learned about
Object#tap.
He used it on a hash.

I've used it here on an array.
Is there any problem using Object#tap in this way?
I saw some examples, but in the examples the object was not modified
in the block.



class Array
def spread(n)
dup.tap{|a| (size-n).downto(1).map{|b| size*b/(size-n+1)}.each{|c|
a.delete_at(c)}}
end
end

arr = (1..12).to_a
(3..12).each{|t| p arr.spread(t)}



###Output

[1, 6, 12]
[1, 4, 8, 12]
[1, 3, 6, 9, 12]
[1, 3, 5, 8, 10, 12]
[1, 2, 4, 6, 8, 10, 12]
[1, 2, 4, 6, 7, 9, 11, 12]
[1, 2, 3, 5, 6, 8, 9, 11, 12]
[1, 2, 3, 4, 6, 7, 8, 10, 11, 12]
[1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]


Harry

From: David Masover on
On Wednesday, July 28, 2010 09:03:18 am Harry Kakueki wrote:
> Is there any problem using Object#tap in this way?
> I saw some examples, but in the examples the object was not modified
> in the block.

Oh, you mean modifying the array?

> class Array
> def spread(n)
> dup.tap{|a| (size-n).downto(1).map{|b| size*b/(size-n+1)}.each{|c|
> a.delete_at(c)}}
> end
> end

Not particularly. The thing you have to be careful of is reassigning it -- for
example, this wouldn't work:

1.tap {|x| x+=1}

You have to actually modify the object. For example, if we're talking about
arrays, instead of this:

string.tap {|x| x + 'foo'}

Do this:

string.tap {|x| x << 'foo'}

It seems like << returns self, so that's completely unnecessary, you could
just do this:

(string << 'foo')

...but hopefully it illustrates the point.

I have a feeling I'm overcomplicating things, though. Here's one possible
implementation of Object#tap:

class Object
def tap
yield self
self
end
end

Nothing mysterious about it at all. (MRI might do it in C, I'm not sure, but
the above works.)

From: Gavin Sinclair on
On Thu, Jul 29, 2010 at 12:40 PM, David Masover <ninja(a)slaphack.com> wrote:

> Do this:
>
> string.tap {|x| x << 'foo'}
>

A nice use of #tap (IMO, and these things are very much a matter of opinion):

message = String.new.tap { |s|
s << "..."
s << "..."
if some_condition?
s << "..."
else
s << "..."
end
end

Gavin