Forum: Ruby Array.which_long? ( I coded an extension for Array )

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Billy H. (Guest)
on 2007-04-29 17:45
(Received via mailing list)
Hi, I'm CFC
I'm new at here.
Nice to meet you:)

I just coded an extension for Array.
It will return the longest element of an array.
Source:

class Array
  def which_long?
    # Version 1.0
    # Coded by CFC < zusocfc @ gmail . com >
    # PLEASE DO NOT REMOVE THE COMMENT OF THIS FUNCTION, THANKS A LOT.
    # Usage:
    #   ['a', 'ab', 'abc' 1234].which_long?
    #   => 1234
    max, long, self_cpy = 0, "", []
    self.size.times{|i| self_cpy << self[i].to_s}
    self_cpy.each{|item| (max = item.size; long = item) if item.size >
max }
    long
  end
end

Usage:
  puts [1, 23, '456'].which_long?
  => 456

CFC --
Chris C. (Guest)
on 2007-04-29 18:12
(Received via mailing list)
On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
> Hi, I'm CFC
> I'm new at here.
> Nice to meet you:)
>
 > I just coded an extension for Array.
>     #   => 1234
>
> CFC --
>
How about:
class Array
  def longest
    self.map {|x| x.to_s }.sort_by {|x| x.size}[-1]
  end
end
David A. Black (Guest)
on 2007-04-29 18:13
(Received via mailing list)
Hi --

On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
> Hi, I'm CFC
> I'm new at here.
> Nice to meet you:)

Welcome!

>     #   ['a', 'ab', 'abc' 1234].which_long?
>   => 456
You're doing too much work -- let Ruby do it :-)

  class Array
    def longest
      map {|e| e.to_s }.max
    end
  end


David
Harry (Guest)
on 2007-04-29 18:15
(Received via mailing list)
On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
>     # Version 1.0
> end
>
> Usage:
>   puts [1, 23, '456'].which_long?
>   => 456
>
> CFC --
>

Hi,

Welcome.

You may be interested in this.
I did not study your code well but I think it is doing something
similar.

p [1, 23, '456'].max {|x,y| x.to_s.size <=> y.to_s.size}

Harry
Robert D. (Guest)
on 2007-04-29 18:17
(Received via mailing list)
On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
> Hi, I'm CFC
> I'm new at here.
> Nice to meet you:)
Likewise and welcome to the list :)

>
> I just coded an extension for Array.
> It will return the longest element of an array.
I hope you posted this for comments, if not just ignore my post, you
will be in good company ;)

Before I go into the details, one important point, ruby classes are
open which is one of the features of Ruby I like most, *but* be
careful with this, I use it a lot, but my rule is, never do this in a
library, or a program that might be designed for reuse, exceptions are
of course libraries which just do that, IOW libraries that are
designed and documented as an extensions of a core class.
>     max, long, self_cpy = 0, "", []
>     self.size.times{|i| self_cpy << self[i].to_s}
>     self_cpy.each{|item| (max = item.size; long = item) if item.size > max }
>     long
>   end
> end
>
def longest
  ... forget it skipping to David's reply
Robert D. (Guest)
on 2007-04-29 18:22
(Received via mailing list)
On 4/29/07, David A. Black <removed_email_address@domain.invalid> wrote:
> You're doing too much work -- let Ruby do it :-)
... for sure, but
>
>   class Array
>     def longest
>       map {|e| e.to_s }.max
>     end
>   end
I think it is not exactly what OP wanted
because %w{x aaaa}.max is "x"
so I will try to comply to his needs
def longest
    map{ |e| [e.to_s.size, e.to_s]}.max.first
end

HTH
Robert
David A. Black (Guest)
on 2007-04-29 18:39
(Received via mailing list)
Hi --

On 4/29/07, Robert D. <removed_email_address@domain.invalid> wrote:
> because %w{x aaaa}.max is "x"
> so I will try to comply to his needs
> def longest
>     map{ |e| [e.to_s.size, e.to_s]}.max.first
> end

You're right that I was wrong (because I didn't do the .size thing),
but yours gives you an integer:

  ['x', 'aaaa'].longest  # => 4

I think you'd have to reverse your array. See Harry's code too, which
uses a block with max.  You could also do:

     sort_by {|e| e.to_s.size }[-1]

(since there's no max_by :-)


David
Billy H. (Guest)
on 2007-04-29 18:54
(Received via mailing list)
Thanks for your reply, I learned more on this thread :P
But I have a question:
If I have an array contain:
  ary = [1, 12, 234, "456"]
there has two elements which size is 3, but the longest method just
returned
one of them.
I can't solve it :(

thank you, Chris, David, Harry and Robert :D

CFC --

2007/4/29, David A. Black <removed_email_address@domain.invalid>:
David A. Black (Guest)
on 2007-04-29 19:04
(Received via mailing list)
Hi --

On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
> Thanks for your reply, I learned more on this thread :P
> But I have a question:
> If I have an array contain:
>   ary = [1, 12, 234, "456"]
> there has two elements which size is 3, but the longest method just returned
> one of them.
> I can't solve it :(

It depends how you want to break the tie.  Here's a way to do it where
a size tie is broken by string comparison, which is ASCII-based.  The
nonzero? method will return -1 or 1 if the two string sizes are not
equal.  If they are equal, the comparison will evaluate to zero and
nonzero? will be false -- which means the second comparison (the ASCII
one) will be executed.

I've included some tests too.

class Array
  def longest
    sort do |a,b|
      (a.to_s.size <=> b.to_s.size).nonzero? ||
      a.to_s <=> b.to_s
    end[-1]
  end
end

require 'test/unit'

class MaxTest < Test::Unit::TestCase

  def test_all_strings
    assert_equal("David", %w{ Da David Dav }.longest)
  end

  def test_all_numbers
    assert_equal(34567, [123,12345,200,34567].longest)
  end

  def test_tie
    assert_equal("David", %w{ David Alan Black }.longest)
  end

  def test_mixed
    assert_equal("David", [123, "David", 456].longest)
  end

  def test_mixed_tie
    assert_equal("David", [12345, "David", "Black", 123, 98765].longest)
  end
end


David
Robert D. (Guest)
on 2007-04-29 19:08
(Received via mailing list)
On 4/29/07, David A. Black <removed_email_address@domain.invalid> wrote:
> > >     end
>
>   ['x', 'aaaa'].longest  # => 4
>
> I think you'd have to reverse your array.
Together we might get there ;), maybe just applying #last instead of
#first.
 See Harry's code too, which
> uses a block with max.
Which is great, I admit that is the nicest solution, learned something
again :)
You could also do:
>
>      sort_by {|e| e.to_s.size }[-1]
That's nice too, (personally I prefer #last to [-1])
>
> (since there's no max_by :-)
yet
>
>
Cheers
Robert
Robert D. (Guest)
on 2007-04-29 19:22
(Received via mailing list)
On 4/29/07, David A. Black <removed_email_address@domain.invalid> wrote:
> Hi --
>
> On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
> > Thanks for your reply, I learned more on this thread :P
> > But I have a question:
> > If I have an array contain:
> >   ary = [1, 12, 234, "456"]
> > there has two elements which size is 3, but the longest method just returned
> > one of them.
> > I can't solve it :(
Alternatively I can use my erroneous code from above to give you all
longest elements
def longest
   longest_size = map{ |e| [e.to_s.size, e.to_s]}.max.first
   reject{ |x| x.size < longest}
end

this is slow though, maybe the following is preferable - but not so
readable -
  def longest
           inject([]){ |s, e|
                  if s.empty? || s.first.size < e.to_s.size then [e]
                  elsif s.first.size == e.to_s.size then s << e
                  else s
                  end
                }
end

> <tie breaking solutions snipped>
Robert
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw
James G. (Guest)
on 2007-04-29 19:25
(Received via mailing list)
On Apr 29, 2007, at 9:38 AM, David A. Black wrote:

>> >     end
>
>  ['x', 'aaaa'].longest  # => 4
>
> I think you'd have to reverse your array. See Harry's code too, which
> uses a block with max.  You could also do:
>
>     sort_by {|e| e.to_s.size }[-1]
>
> (since there's no max_by :-)

Well, not yet:

$ ruby_yarv -e 'p %w[c bb aaa].max_by { |e| e.to_s.size }'
"aaa"

James Edward G. II
Robert D. (Guest)
on 2007-04-29 19:39
(Received via mailing list)
On 4/29/07, James Edward G. II <removed_email_address@domain.invalid> wrote:

> > (since there's no max_by :-)
>
> Well, not yet:
when I said that above I just dreamt, I had no clue, conclusion =>
YARV fulfills your wildest dreams ;)
>
> $ ruby_yarv -e 'p %w[c bb aaa].max_by { |e| e.to_s.size }'
> "aaa"
 I guess there will be a #min_by too,
how does it break ties? Well I ask too much I gotta go the last
snapshot...

BTW instead of
   a[ rand(a.size) ]
we can write
   a.max_by{ rand }
now; LOL!

Robert
Harry (Guest)
on 2007-04-30 02:14
(Received via mailing list)
On 4/29/07, Billy H. <removed_email_address@domain.invalid> wrote:
> Thanks for your reply, I learned more on this thread :P
> But I have a question:
> If I have an array contain:
>   ary = [1, 12, 234, "456"]
> there has two elements which size is 3, but the longest method just returned
> one of them.
> I can't solve it :(
>

Is this what you are looking for?
Do you want all longest elements?

big = [1, 12, 234,45,978, "456"].max {|x,y| x.to_s.size <=> y.to_s.size}
p [1, 12, 234,45,978, "456"].select {|r| r.to_s.size == big.to_s.size}

Harry
Billy H. (Guest)
on 2007-04-30 05:19
(Received via mailing list)
Hi,
Harry, thanks :D
Robert K. (Guest)
on 2007-04-30 14:00
(Received via mailing list)
On 29.04.2007 16:11, Chris C. wrote:
>>   def which_long?
>>     long
> class Array
>  def longest
>    self.map {|x| x.to_s }.sort_by {|x| x.size}[-1]
>  end
> end

Thank you for leaving the #inject solutions to me. :-)

irb(main):001:0> %w{a ab abc 123 34}.inject{|a,b| a.size > b.size ? a :
b}
=> "123"
irb(main):002:0> %w{a ab abc 123 34}.inject{|a,b| a.size >= b.size ? a :
b}
=> "abc"

Kind regards

  robert
Robert D. (Guest)
on 2007-04-30 14:40
(Received via mailing list)
On 4/30/07, Robert K. <removed_email_address@domain.invalid> wrote:
> >> class Array
> >> max }
> > How about:
> > class Array
> >  def longest
> >    self.map {|x| x.to_s }.sort_by {|x| x.size}[-1]
> >  end
> > end
>
> Thank you for leaving the #inject solutions to me. :-)
Are you kidding I posted an inject solution 19h ago ;)

But it was to return an array of all longest elements, I guess you can
maybe refine it, it seems clumsy, so I repost it just if you have some
time to play ;)

def longest
          inject([]){ |s, e|
                 if s.empty? || s.first.size < e.to_s.size then [e]
                 elsif s.first.size == e.to_s.size then s << e
                 else s
                 end
               }
end
>
> irb(main):001:0> %w{a ab abc 123 34}.inject{|a,b| a.size > b.size ? a : b}
> => "123"
> irb(main):002:0> %w{a ab abc 123 34}.inject{|a,b| a.size >= b.size ? a : b}

You get full credits for this anyway it is really beautiful, can you
stop being so clever ;).

Cheers
Robert
Robert K. (Guest)
on 2007-04-30 15:50
(Received via mailing list)
On 30.04.2007 12:39, Robert D. wrote:
>> >>
>> >>     self_cpy.each{|item| (max = item.size; long = item) if item.size >
>> >>
>> > How about:
>> > class Array
>> >  def longest
>> >    self.map {|x| x.to_s }.sort_by {|x| x.size}[-1]
>> >  end
>> > end
>>
>> Thank you for leaving the #inject solutions to me. :-)
> Are you kidding I posted an inject solution 19h ago ;)

I am sorry, I did not see it.

>               }
> end

Hm, I'd probably use case here.  Let's see...

def longest
   inject([]) do |lg, e|
     case
       when lg.empty?, lg.first.size == e.size
         lg << e
       when lg.first.size < e.size
         [e]
       else
         lg
     end
   end
end

Alternative, but with higher memory consumption

def longest
   lg = Hash.new {|h,k| h[k] = []}
   each {|x| lg[x.size] << x}
   lg.sort_by {|k,v| k}.last.pop
end

>> irb(main):001:0> %w{a ab abc 123 34}.inject{|a,b| a.size > b.size ? a
>> : b}
>> => "123"
>> irb(main):002:0> %w{a ab abc 123 34}.inject{|a,b| a.size >= b.size ? a
>> : b}
>
> You get full credits for this anyway it is really beautiful, can you
> stop being so clever ;).

Since I overlooked your posting I can't be so clever, can I? :-)

With #inject it's really special, it took me a while to pick it up and
now I can't stop using it.  IIRC I even went to the exercise to
implement all methods in Enumerable by using #inject - maybe you can
find it in the archives. :-)

Kind regards

  robert
Daniel M. (Guest)
on 2007-04-30 16:09
(Received via mailing list)
"Robert D." <removed_email_address@domain.invalid> writes:

>               }
> end


That does seem clumsy.  How about:

class Array
  def longest
    inject([0,[]]) { |(s,l),e|
      if e.to_s.size == s then [s,l << e]
      elsif e.to_s.size < s then [s,l]
      else [e.to_s.size, [e]]
      end
    }[1]
  end
end

Gotta love those destructuring block parameters.
Robert D. (Guest)
on 2007-04-30 18:12
(Received via mailing list)
On 4/30/07, Robert K. <removed_email_address@domain.invalid> wrote:

>
> I am sorry, I did not see it.
I was just kidding Robert.
> >                 end
> >               }
> > end

>        else
>          lg
>      end
>    end
> end
better already, I am still looking for *the* solution
>
> Alternative, but with higher memory consumption
>
> def longest
>    lg = Hash.new {|h,k| h[k] = []}
>    each {|x| lg[x.size] << x}
>    lg.sort_by {|k,v| k}.last.pop
> end
good idea but I wanted inject :)
> <snip>

Robert
Robert K. (Guest)
on 2007-04-30 19:25
(Received via mailing list)
On 30.04.2007 16:11, Robert D. wrote:
> On 4/30/07, Robert K. <removed_email_address@domain.invalid> wrote:
>
>> I am sorry, I did not see it.
> I was just kidding Robert.

But I *did* overlook your posting.  Honestly. :-)

>> >               }
>>        when lg.first.size < e.size
>> def longest
>>    lg = Hash.new {|h,k| h[k] = []}
>>    each {|x| lg[x.size] << x}
>>    lg.sort_by {|k,v| k}.last.pop
>> end
> good idea but I wanted inject :)
>> <snip>

That's an easy transformation (left as exercise for the reader, bonus
points for a one liner). :-)

Cheers

  robert
William J. (Guest)
on 2007-05-01 00:05
(Received via mailing list)
On Apr 30, 6:47 am, Robert K. <removed_email_address@domain.invalid> wrote:
>
> >> >>     #   ['a', 'ab', 'abc' 1234].which_long?
> >> >>   puts [1, 23, '456'].which_long?
>
> >          inject([]){ |s, e|
>    inject([]) do |lg, e|
>
> Alternative, but with higher memory consumption
>
> def longest
>    lg = Hash.new {|h,k| h[k] = []}
>    each {|x| lg[x.size] << x}
>    lg.sort_by {|k,v| k}.last.pop
> end

def longest
    max = map{|s| s.size}.max
    select{|s| s.size == max}
end
Robert D. (Guest)
on 2007-05-01 02:04
(Received via mailing list)
On 4/30/07, Robert K. <removed_email_address@domain.invalid> wrote:
<snip>
> points for a one liner). :-)
inject( Hash.new{ |h,k| h[k]=[]} ){|h,e| h[e.size] << e}.sort_by....

as this is not readable anymore let me golf a little bit

inject([]){|a,e| a[e.size] = (a[e.size]||[])+[e];a}.last
hmm that is not too bad ;)

Robert
Robert K. (Guest)
on 2007-05-01 11:16
(Received via mailing list)
On 01.05.2007 00:03, Robert D. wrote:
>>
>> That's an easy transformation (left as exercise for the reader, bonus
>> points for a one liner). :-)
>
> inject( Hash.new{ |h,k| h[k]=[]} ){|h,e| h[e.size] << e}.sort_by....
                                                       ^^^^
The return from the block is missing. :-)

> as this is not readable anymore let me golf a little bit
>
> inject([]){|a,e| a[e.size] = (a[e.size]||[])+[e];a}.last
> hmm that is not too bad ;)

Couldn't you just use ||= here?

inject([]){|a,e|(a[e.size]||=[])<<e;a}.last

I like your idea to use the length as array index - that way no sorting
is needed.  Brilliant!

Kind regards

  robert
Robert D. (Guest)
on 2007-05-01 11:26
(Received via mailing list)
On 5/1/07, Robert K. <removed_email_address@domain.invalid> wrote:
> >> >> <snip>
> >>
> >> That's an easy transformation (left as exercise for the reader, bonus
> >> points for a one liner). :-)
> >
> > inject( Hash.new{ |h,k| h[k]=[]} ){|h,e| h[e.size] << e}.sort_by....
>                                                        ^^^^
> The return from the block is missing. :-)
Yeah I did not like this so I did not test it, I forgot the return of
the block in the solution below too, but I liked the solution and
therefore tested it....
>
> > as this is not readable anymore let me golf a little bit
> >
> > inject([]){|a,e| a[e.size] = (a[e.size]||[])+[e];a}.last
> > hmm that is not too bad ;)
>
> Couldn't you just use ||= here?
>
> inject([]){|a,e|(a[e.size]||=[])<<e;a}.last
Indeed, I guess I was very tired!!!
Now the solutions complexity and length just seems right.
Thanks for getting this right.
>
> I like your idea to use the length as array index - that way no sorting
> is needed.  Brilliant!
Well that is grossly exaggerated, but thank you anyway, the idea was
yours of course I just used an Array instead of a Hash, that must be
my tiny Lua background.

Cheers
Robert
William J. (Guest)
on 2007-05-02 04:56
(Received via mailing list)
On May 1, 2:26 am, "Robert D." <removed_email_address@domain.invalid> wrote:
> > >> >> end
> Yeah I did not like this so I did not test it, I forgot the return of
> > inject([]){|a,e|(a[e.size]||=[])<<e;a}.last
> my tiny Lua background.
>
> Cheers
> Robert

I wondered whether these rather convoluted solutions had the
redeeming feature of being faster than a simple and natural
solution.  It turned out that they are slower:

             user     system      total        real
simple   0.671000   0.010000   0.681000 (  0.711000)
dober1   1.472000   0.010000   1.482000 (  1.512000)
klemme1  1.261000   0.000000   1.261000 (  1.292000)
klemme2  2.324000   0.010000   2.334000 (  2.363000)
dober2   1.903000   0.000000   1.903000 (  1.963000)
klemme3  1.211000   0.000000   1.211000 (  1.242000)
martin   1.663000   0.000000   1.663000 (  1.692000)

Here's the benchmark code:

require 'benchmark'

# Find longest strings.
class Array
  def simple
    max = map{|s| s.size}.max
    select{|s| s.size == max}
  end

  def dober1
    inject([]){ |s, e|
      if s.empty? || s.first.size < e.to_s.size then [e]
      elsif s.first.size == e.to_s.size then s << e
      else s
      end
    }
  end

  def klemme1
     inject([]) do |lg, e|
       case
         when lg.empty?, lg.first.size == e.size
           lg << e
         when lg.first.size < e.size
           [e]
         else
           lg
       end
     end
  end

  def klemme2
     lg = Hash.new {|h,k| h[k] = []}
     each {|x| lg[x.size] << x}
     lg.sort_by {|k,v| k}.last.pop
  end

  def dober2
    inject([]){|a,e| a[e.size] = (a[e.size]||[])+[e]
      a}.last
  end

  def klemme3
    inject([]){|a,e|(a[e.size]||=[])<<e;a}.last
  end

  def martin
    inject([0,[]]) { |(s,l),e|
      if e.to_s.size == s then [s,l << e]
      elsif e.to_s.size < s then [s,l]
      else [e.to_s.size, [e]]
      end
    }[1]
  end

end

methods = %w(simple dober1
  klemme1 klemme2 dober2 klemme3 martin)

words = %w(posit that it suffices that the past
  is exempt from mutation)

# Verify that all methods produce same result.
p methods.map{|method| words.send( method )}.uniq
puts

Benchmark.bm( 7 )  do |bm|

  methods.each{|method|
    bm.report( method ) do
      10_000.times{ words.send( method ) }
    end
  }

end
Robert K. (Guest)
on 2007-05-02 15:11
(Received via mailing list)
On 02.05.2007 02:50, William J. wrote:
>>>>>>> end
>>
>>> is needed.  Brilliant!
>
>
>     inject([]){ |s, e|
>          when lg.empty?, lg.first.size == e.size
>      lg = Hash.new {|h,k| h[k] = []}
>     inject([]){|a,e|(a[e.size]||=[])<<e;a}.last
>
> puts
>
Actually you forgot an an even simpler solution - although it is not as
short as the other ones.  Probably better call it "more
straightforward":

   def simple2
     res = []
     len = 0

     each do |s|
       case s.length <=> len
         when 1
           len = s.length
           res.clear << s
         when 0
           res << s
         when -1
           # too short, ignore
         else
           raise "Wrong comparison result: #{s.length <=> len}"
       end
     end

     res
   end


13:00:10 [Temp]: ./maxing.rb
[["suffices", "mutation"]]

              user     system      total        real
simple   0.235000   0.000000   0.235000 (  0.239000)
simple2  0.219000   0.000000   0.219000 (  0.187000)
dober1   0.437000   0.000000   0.437000 (  0.435000)
klemme1  0.407000   0.000000   0.407000 (  0.401000)
klemme2  0.734000   0.000000   0.734000 (  0.765000)
dober2   0.656000   0.000000   0.656000 (  0.658000)
klemme3  0.344000   0.000000   0.344000 (  0.376000)
martin   0.531000   0.000000   0.531000 (  0.529000)

The reason is - of course - that you need to traverse the array only
once.

Btw, any idea why I'm seeing this if I replace "bm" with "bmbm"?

13:00:44 [Temp]: ./maxing.rb
[["suffices", "mutation"]]

Rehearsal -------------------------------------------
simple  ./maxing.rb:99:in `send': undefined method `simple ' for
#<Array:0x104226b4> (NoMethodError)
         from ./maxing.rb:99
         from ./maxing.rb:99:in `times'
         from ./maxing.rb:99
         from /usr/lib/ruby/1.8/benchmark.rb:293:in `measure'
         from /usr/lib/ruby/1.8/benchmark.rb:261:in `bmbm'
         from /usr/lib/ruby/1.8/benchmark.rb:259:in `each'
         from /usr/lib/ruby/1.8/benchmark.rb:259:in `bmbm'
         from ./maxing.rb:95

Even though "simple" is reported an instance method of Arrray?

Kind regards

  robert
Robert D. (Guest)
on 2007-05-02 23:00
(Received via mailing list)
On 5/2/07, William J. <removed_email_address@domain.invalid> wrote:
> On May 1, 2:26 am, "Robert D." <removed_email_address@domain.invalid> wrote:
> > On 5/1/07, Robert K. <removed_email_address@domain.invalid> wrote:
> >
<interesting but long BM snipped>
Please be aware that inject is quite slow, I guess it could be
optimized but I am not sure.
I still think you should write the code you feel is the nicest/most
readable/most concise before optimizing.

That does *not* mean that I did not read the benchmarks with interest :)

Cheers
Robert
William J. (Guest)
on 2007-05-03 02:06
(Received via mailing list)
On May 2, 6:05 am, Robert K. <removed_email_address@domain.invalid> wrote:
> >>>>>>> def longest
> >>> The return from the block is missing. :-)
> >> Now the solutions complexity and length just seems right.
>
> > klemme3  1.211000   0.000000   1.211000 (  1.242000)
> >     select{|s| s.size == max}
>
> >      end
> >       a}.last
> >       else [e.to_s.size, [e]]
> >   is exempt from mutation)
> >     end
>
>            raise "Wrong comparison result: #{s.length <=> len}"
> simple   0.235000   0.000000   0.235000 (  0.239000)
> simple2  0.219000   0.000000   0.219000 (  0.187000)
> dober1   0.437000   0.000000   0.437000 (  0.435000)
> klemme1  0.407000   0.000000   0.407000 (  0.401000)
> klemme2  0.734000   0.000000   0.734000 (  0.765000)
> dober2   0.656000   0.000000   0.656000 (  0.658000)
> klemme3  0.344000   0.000000   0.344000 (  0.376000)
> martin   0.531000   0.000000   0.531000 (  0.529000)

Although this is faster, it would take me a lot longer,
starting from scratch, to understand it than to understand
the 2-line "simple" method.

> #<Array:0x104226b4> (NoMethodError)
>          from ./maxing.rb:99
>          from ./maxing.rb:99:in `times'
>          from ./maxing.rb:99
>          from /usr/lib/ruby/1.8/benchmark.rb:293:in `measure'
>          from /usr/lib/ruby/1.8/benchmark.rb:261:in `bmbm'
>          from /usr/lib/ruby/1.8/benchmark.rb:259:in `each'
>          from /usr/lib/ruby/1.8/benchmark.rb:259:in `bmbm'
>          from ./maxing.rb:95
>
> Even though "simple" is reported an instance method of Arrray?

I noticed the same thing during my testing.
Benchmark tacks a space onto the "method" string.
A simple fix:
      10_000.times{ words.send( method.strip ) }
Charles L. (Guest)
on 2007-05-03 17:00
Similar to Robert K.'s above:

module Enumerable
  def longest
    group_by { |a| a.to_s.size }.max.last
  end
end
Rick D. (Guest)
on 2007-05-03 18:28
(Received via mailing list)
On 4/29/07, James Edward G. II <removed_email_address@domain.invalid> wrote:
> On Apr 29, 2007, at 9:38 AM, David A. Black wrote:

> "aaa"
Actually  Array#max already takes a block, and the Rdoc actually uses
almost this very use case to document it:

$ qri Array#max
--------------------------------------------------------- Enumerable#max
     enum.max                   => obj
     enum.max {|a,b| block }    => obj
------------------------------------------------------------------------
     Returns the object in enum with the maximum value. The first form
     assumes all objects implement Comparable; the second uses the
     block to return a <=> b.

        a = %w(albatross dog horse)
        a.max                                  #=> "horse"
        a.max {|a,b| a.length <=> b.length }   #=> "albatross"


Harry gave a solution along these lines early on in the thread, but no
one seems to have noticed.

The observation that 1.9 is adding max_by is interesting, but it's
more a matter of syntactic sugar than the difference between sort and
sort_by since max only needs to evaluate the block once for each
element.

Now max_by is nicer since the block just needs to return the
comparison value rather than a comparison result.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
This topic is locked and can not be replied to.