Cleaner way to do this?

Discussion in 'Ruby' started by Harry Ohlsen, Nov 5, 2004.

  1. Harry Ohlsen

    Harry Ohlsen Guest

    Hi,

    One of my colleagues asked me last night how he could do some processing
    on every object of an array, with different processing for the first
    item ... but without generating an intermediate variable.

    An example would be doing the equivalent of

    puts a.join(", ")

    without having a temporary string created. The temporary string isn't
    an issue normally, but imagine if the array is huge.

    Trying to make it reasonably flexible, I came up with the following, but
    I figure there's probably some cleaner way to do it.

    Maybe there's a method I don't know about that allows for this kind of
    thing. Any suggestions?

    Pardon the method name ... it's only a model :)

    class Array
    def first_and_rest(first_time)
    first_time.call self[0]

    (1 .. self.length - 1).each do |i|
    yield self
    end
    end
    end

    a = [1, 2, 3, 4, 5]

    File.open("test.txt", "w") do |out|
    a.first_and_rest(proc {|x| out.print x}) do |x|
    out.print ", #{x}"
    end

    out.puts
    end


    ************************************************************************

    If you have received this e-mail in error, please delete it and notify the sender as soon as possible. The contents of this e-mail may be confidential and the unauthorized use, copying, or dissemination of it and any attachments to it, is prohibited.

    Internet communications are not secure and Hyperion does not, therefore, accept legal responsibility for the contents of this message nor for any damage caused by viruses. The views expressed here do not necessarily represent those of Hyperion.

    For more information about Hyperion, please visit our Web site at www.hyperion.com
     
    Harry Ohlsen, Nov 5, 2004
    #1
    1. Advertising

  2. How about

    [1, 2, 3, 4, 5].each_with_index do |x, i|
    if i == 0
    print x
    else
    print ", ",x
    end
    end

    Wayne

    -----
    No Bugs Software
    "Ruby and C++ Contract Programming in Silicon Valley"
     
    Wayne Vucenic, Nov 5, 2004
    #2
    1. Advertising

  3. Harry Ohlsen

    Guest

    On Fri, 5 Nov 2004, Harry Ohlsen wrote:

    > Hi,
    >
    > One of my colleagues asked me last night how he could do some processing
    > on every object of an array, with different processing for the first
    > item ... but without generating an intermediate variable.
    >
    > An example would be doing the equivalent of
    >
    > puts a.join(", ")
    >
    > without having a temporary string created. The temporary string isn't
    > an issue normally, but imagine if the array is huge.
    >
    > Trying to make it reasonably flexible, I came up with the following, but
    > I figure there's probably some cleaner way to do it.
    >
    > Maybe there's a method I don't know about that allows for this kind of
    > thing. Any suggestions?
    >
    > Pardon the method name ... it's only a model :)
    >
    > class Array
    > def first_and_rest(first_time)
    > first_time.call self[0]
    >
    > (1 .. self.length - 1).each do |i|
    > yield self
    > end
    > end
    > end
    >
    > a = [1, 2, 3, 4, 5]
    >
    > File.open("test.txt", "w") do |out|
    > a.first_and_rest(proc {|x| out.print x}) do |x|
    > out.print ", #{x}"
    > end
    >
    > out.puts
    > end


    hard to profile with IO involved but:

    harp:~ > ruby a.rb
    1048576
    -------------------------------------------------------------------------------
    first_and_rest
    -------------------------------------------------------------------------------
    7.89007091522217
    549755289600
    -------------------------------------------------------------------------------
    ruby objects are copy on write references - no copy is made here!
    -------------------------------------------------------------------------------
    6.67814898490906
    549755289600
    -------------------------------------------------------------------------------
    is testing __really__ that slow?
    -------------------------------------------------------------------------------
    13.0074229240417
    549755289600

    harp:~ > cat a.rb
    def time label
    puts('-' * 79)
    puts label
    puts('-' * 79)
    a = Time::now
    yield
    b = Time::now
    puts(b.to_f - a.to_f)
    end

    class Array
    def first_and_rest(first_time)
    first_time.call self[0]
    (1 .. self.length - 1).each do |i|
    yield self
    end
    end
    end

    huge = (0...(2 ** 20)).to_a
    p huge.size


    sum = 0
    time('first_and_rest') do
    huge.first_and_rest(proc {|x| sum += x}) do |x|
    sum += x
    end
    end
    p sum

    sum = 0
    time('ruby objects are copy on write references - no copy is made here!') do
    first = huge.first
    sum += first
    huge.last(huge.size - 1).each{|x| sum += x}
    end
    p sum

    sum = 0
    time('is testing __really__ that slow?') do
    huge.each_with_index do |x, i|
    sum += (i == 0 ? (x * 2) : x)
    end
    end
    p sum


    so testing is slow, however i couldn't really tell the difference until a
    million entries or so. in any case i think your friend isn't clear on the
    meaning of 'created' - unless you modify the first element no copy is made -
    you just get a reference which costs basically nothing. to prove it:

    harp:~ > ruby b.rb
    1048576
    -------------------------------------------------------------------------------
    it's plenty fast to take references
    -------------------------------------------------------------------------------
    3.60012054443359e-05
    -------------------------------------------------------------------------------
    but slow(er) if you actually copy on write
    -------------------------------------------------------------------------------
    36.049026966095


    harp:~ > cat b.rb
    def time label
    puts('-' * 79)
    puts label
    puts('-' * 79)
    a = Time::now
    yield
    b = Time::now
    puts(b.to_f - a.to_f)
    end

    huge = '_' * (2 ** 20)
    p huge.size


    time("it's plenty fast to take references"){ 42.times{ s = huge } }
    time("but slow(er) if you actually copy on write"){ 42.times{ (s = huge).gsub(%r/./,'!') } }


    IMHO the copy on write semantics of ruby assignment is one of it's nicest
    features - it's a lot easier to shoot your self in the foot with memory
    allocation in perl.


    kind regards.

    -a
    --
    ===============================================================================
    | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
    | PHONE :: 303.497.6469
    | When you do something, you should burn yourself completely, like a good
    | bonfire, leaving no trace of yourself. --Shunryu Suzuki
    ===============================================================================
     
    , Nov 5, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Salerno
    Replies:
    13
    Views:
    487
    Boris Borcic
    Aug 3, 2006
  2. John Salerno

    cleaner way to write this?

    John Salerno, Oct 25, 2006, in forum: Python
    Replies:
    29
    Views:
    601
    John Salerno
    Oct 26, 2006
  3. Peter Olcott

    Is there a cleaner way to do this?

    Peter Olcott, Dec 6, 2005, in forum: C++
    Replies:
    7
    Views:
    364
    Peter Olcott
    Dec 7, 2005
  4. Darrel

    Cleaner way to write this?

    Darrel, Mar 20, 2007, in forum: ASP .Net
    Replies:
    1
    Views:
    279
    Cowboy \(Gregory A. Beamer\)
    Mar 20, 2007
  5. Fencer
    Replies:
    6
    Views:
    356
    Fencer
    Jul 29, 2010
Loading...

Share This Page