yield/block question

Discussion in 'Ruby' started by Kenneth McDonald, Sep 10, 2008.

  1. This is something I know how to do in Python, but it's got me
    flummoxed in Ruby--I still haven't fully gotten my head around the
    Ruby way. ("yield" means something very different in Python and in Ruby.

    Let's say I have a data structure consisting of nested Arrays and
    numbers, for example [[1,2], 3, [[4]]]. I want to write an extension
    to Array, "each_leaf", which takes a block that will be applied to
    each number sequentially in that nested array. For example, if arr is
    the given array, then

    result = 0
    arr.each_leaf {|n| result += n}

    would end with result being equal to 1+2+3+4

    Could anyone help out? Much appreciated.

    Thanks,
    Ken
     
    Kenneth McDonald, Sep 10, 2008
    #1
    1. Advertising

  2. On Tue, Sep 9, 2008 at 5:04 PM, Kenneth McDonald
    <> wrote:
    > This is something I know how to do in Python, but it's got me flummoxed in
    > Ruby--I still haven't fully gotten my head around the Ruby way. ("yield"
    > means something very different in Python and in Ruby.
    >
    > Let's say I have a data structure consisting of nested Arrays and numbers,
    > for example [[1,2], 3, [[4]]]. I want to write an extension to Array,
    > "each_leaf", which takes a block that will be applied to each number
    > sequentially in that nested array. For example, if arr is the given array,
    > then
    >
    > result = 0
    > arr.each_leaf {|n| result += n}
    >
    > would end with result being equal to 1+2+3+4
    >
    > Could anyone help out? Much appreciated.


    array.flatten.each {|i| yield i}

    martin
     
    Martin DeMello, Sep 10, 2008
    #2
    1. Advertising

  3. Kenneth McDonald

    Serabe Guest

    What about this?

    class Array
    def each_leaf(&block)
    each do |x|
    case x
    when Array: x.each_leaf &block
    else block.call x
    end
    end
    end
    end

    arr = [[1,2], 3, [[4]]]
    result = 0
    arr.each_leaf{|n| result += n}

    puts result

    Kind regards,

    Serabe

    P.D. Sorry for no more explanation, but I'm really tired (2:23 am right now).

    --
    http://www.serabe.com
     
    Serabe, Sep 10, 2008
    #3
  4. Very elegant, with the drawback that it requires flattening a
    potentially large array structure.
    But that was carelessness in my lack of specifications. A nice
    solution, thank you.

    Ken


    On Sep 9, 2008, at 7:11 PM, Martin DeMello wrote:

    > On Tue, Sep 9, 2008 at 5:04 PM, Kenneth McDonald
    > <> wrote:
    >> This is something I know how to do in Python, but it's got me
    >> flummoxed in
    >> Ruby--I still haven't fully gotten my head around the Ruby way.
    >> ("yield"
    >> means something very different in Python and in Ruby.
    >>
    >> Let's say I have a data structure consisting of nested Arrays and
    >> numbers,
    >> for example [[1,2], 3, [[4]]]. I want to write an extension to Array,
    >> "each_leaf", which takes a block that will be applied to each number
    >> sequentially in that nested array. For example, if arr is the given
    >> array,
    >> then
    >>
    >> result = 0
    >> arr.each_leaf {|n| result += n}
    >>
    >> would end with result being equal to 1+2+3+4
    >>
    >> Could anyone help out? Much appreciated.

    >
    > array.flatten.each {|i| yield i}
    >
    > martin
    >
     
    Kenneth McDonald, Sep 10, 2008
    #4
  5. Perfect, just what I was looking for. Thanks,
    Ken


    On Sep 9, 2008, at 7:17 PM, Serabe wrote:

    > What about this?
    >
    > class Array
    > def each_leaf(&block)
    > each do |x|
    > case x
    > when Array: x.each_leaf &block
    > else block.call x
    > end
    > end
    > end
    > end
    >
    > arr = [[1,2], 3, [[4]]]
    > result = 0
    > arr.each_leaf{|n| result += n}
    >
    > puts result
    >
    > Kind regards,
    >
    > Serabe
    >
    > P.D. Sorry for no more explanation, but I'm really tired (2:23 am
    > right now).
    >
    > --
    > http://www.serabe.com
    >
     
    Kenneth McDonald, Sep 10, 2008
    #5
  6. 2008/9/10 Kenneth McDonald <>:
    > On Sep 9, 2008, at 7:17 PM, Serabe wrote:
    >
    >> What about this?
    >>
    >> class Array
    >> def each_leaf(&block)
    >> each do |x|
    >> case x
    >> when Array: x.each_leaf &block
    >> else block.call x
    >> end
    >> end
    >> end
    >> end


    This can be generalized to Enumerable. Still a handicap is that this
    does not gracefully deal with structures which are not cycle free.

    Just some toying around:

    module Enumerable
    def each_leaf(cl = Object, &b)
    each do |el|
    case el
    when String
    yield el if cl === el
    when Enumerable
    el.each_leaf(cl, &b)
    when cl
    yield el
    else
    # ignore
    end
    end
    end
    end

    Kind regards

    robert

    --
    use.inject do |as, often| as.you_can - without end
     
    Robert Klemme, Sep 10, 2008
    #6
    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. morrell
    Replies:
    1
    Views:
    1,006
    roy axenov
    Oct 10, 2006
  2. Adam Atlas
    Replies:
    2
    Views:
    409
    Adam Atlas
    Jun 4, 2007
  3. Replies:
    1
    Views:
    341
    Gabriel Genellina
    Apr 22, 2008
  4. Markus
    Replies:
    1
    Views:
    218
    Mark Hubbart
    Sep 27, 2004
  5. Michael Edgar
    Replies:
    13
    Views:
    306
    Brian Candler
    Apr 21, 2011
Loading...

Share This Page