Array.each restart when array is changed

Hi!

How to restart a "each" iteration when the iterated array is changed? I do
it like this

changed=false
while (changed)
changed=false
array.each {|e|
  if (today_is_christmas)
    array=array+=["Hello santa claus"]
    changed=true
  end
}

Is there a more elegant way to do this?

Second question:
why is this not allowed

#show me the first n letters of the alphabet
('a'...'a'+gets.to_i).each{|e| puts e }

How to do it the right way?

Thanks in advance,
Kevin

Kevin Börgens wrote:

Hi!

How to restart a "each" iteration when the iterated array is changed? I do
it like this

changed=false
while (changed)
changed=false
array.each {|e|
  if (today_is_christmas)
    array=array+=["Hello santa claus"]
    changed=true
  end
}

As I re-read my post, I find it a bit ambituous. It is not important that
directly after the change the iteration is restarted, it is sufficient when
it is restarted when the iteration finishes (like in the above example)

TIA,
Kevin

maybe:

   harp:~ > cat a.rb
   bits = [0, 1, 0, 1]
   n = 0

   begin
     bits.each_with_index do |bit, pos|
       n |= (bit << pos)
       bits << 0 << 1 and raise 'changed' if bits.size == 4 and pos == 3
     end
   rescue => e
     retry
   end

   p n
   printf "%b\n", n

   harp:~ > ruby a.rb
   42
   101010

i don't know if changing an array while iterating is safe though - i'll defer
to someone else on that note.

cheers.

-a

···

On Wed, 10 Nov 2004, Kevin [ISO-8859-15] Börgens wrote:

Hi!

How to restart a "each" iteration when the iterated array is changed? I do
it like this

changed=false
while (changed)
changed=false
array.each {|e|
if (today_is_christmas)
   array=array+=["Hello santa claus"]
   changed=true
end
}

Is there a more elegant way to do this?

Second question:
why is this not allowed

#show me the first n letters of the alphabet
('a'...'a'+gets.to_i).each{|e| puts e }

How to do it the right way?

Thanks in advance,
Kevin

--

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

===============================================================================

Kevin Börgens wrote:

Second question:
why is this not allowed

Because 'a' does not automagically cast to Fixnum.
You have to do 'a'[0] to do that and .chr to get back the
character.

#show me the first n letters of the alphabet
('a'...'a'+gets.to_i).each{|e| puts e }

Try this:

('a'[0]...'a'[0]+gets.to_i).each{|e| puts e.chr}

···

How to do it the right way?

Thanks in advance,
Kevin

Kevin Börgens wrote:

#show me the first n letters of the alphabet
('a'...'a'+gets.to_i).each{|e| puts e }

irb(main):006:0> alpha = 'a'
=> "a"
irb(main):007:0> n = 10
=> 10
irb(main):008:0> n.times {puts alpha; alpha = alpha.succ}
a
b
c
d
e
f
g
h
i
j
=> 10
irb(main):009:0>

[Kevin Börgens <kevin@boergens.de>, 2004-11-10 23.48 CET]

How to restart a "each" iteration when the iterated array is changed? I do
it like this

changed=false
while (changed)
changed=false
array.each {|e|
  if (today_is_christmas)
    array=array+=["Hello santa claus"]
    changed=true
  end
}

array.each do |e|
  if (today_is_christmas)
    array += ["Hello"]
    retry
  end
end

Beware of infinite loops.

Second question:
why is this not allowed

#show me the first n letters of the alphabet
('a'...'a'+gets.to_i).each{|e| puts e }

How to do it the right way?

(?a ... ?a + gets.to_i).each do |e| puts e.chr end

letter='a'; gets.to_i.times do puts letter; letter=letter.succ end

You have several possibilities.

Good luck.

···

--

"Kevin Börgens" <kevin@boergens.de> schrieb im Newsbeitrag
news:2vfjurF2ljhdfU1@uni-berlin.de...

Hi!

How to restart a "each" iteration when the iterated array is changed? I

do

it like this

changed=false
while (changed)
changed=false
array.each {|e|
  if (today_is_christmas)
    array=array+=["Hello santa claus"]

This is sufficient:
array += +=["Hello santa claus"]

    changed=true
  end
}

Is there a more elegant way to do this?

I would not change the array in place while iterating. Without more
knowledge about your scenario I'd do this:

added =

begin
  added.clear

  array.each do |e|
    if (today_is_christmas)
      added << "Hello santa claus"
    end
  end

  array.concat added
end until added.empty?

If you want to ensure, that each element is traversed only once, a queue
approach is better:

queue = array.dup

until queue.empty?
  e = queue.shift

  if today_is_christmas(e)
    x = "Hello santa claus"
    queue << x
    array << x
  end
end

This is much more performant because with the other solution you end up
running through the same array members over and over again.

Are you doing some kind of BFS?

Kind regards

    robert

Kevin Börgens wrote:

#show me the first n letters of the alphabet
('a'...'a'+gets.to_i).each{|e| puts e }

How to do it the right way?

I would just do ('a' .. 'z').to_a.first(gets.to_i)

"Shashank Date" <sdate@everestkc.net> schrieb im Newsbeitrag
news:4192B183.3070204@everestkc.net...

Kevin Börgens wrote:
> Second question:
> why is this not allowed

Because 'a' does not automagically cast to Fixnum.
You have to do 'a'[0] to do that and .chr to get back the
character.

> #show me the first n letters of the alphabet
> ('a'...'a'+gets.to_i).each{|e| puts e }

Try this:

('a'[0]...'a'[0]+gets.to_i).each{|e| puts e.chr}

(?a ... ?a+10).each {|c| puts c.chr}

a
b
c
d
e
f
g
h
i
j
=> 97...107

Regards

    robert

How does this work? Does 'retry' recall the method associated with its block?

Bill

···

On Thu, 11 Nov 2004 21:23:08 +0900, Carlos <angus@quovadis.com.ar> wrote:

[Kevin Börgens <kevin@boergens.de>, 2004-11-10 23.48 CET]
array.each do |e|
        if (today_is_christmas)
                array += ["Hello"]
                retry
        end
end

Hi --

···

On Thu, 11 Nov 2004, Robert Klemme wrote:

"Kevin Börgens" <kevin@boergens.de> schrieb im Newsbeitrag
news:2vfjurF2ljhdfU1@uni-berlin.de...
> Hi!
>
>
> How to restart a "each" iteration when the iterated array is changed? I
do
> it like this
>
> changed=false
> while (changed)
> changed=false
> array.each {|e|
> if (today_is_christmas)
> array=array+=["Hello santa claus"]

This is sufficient:
array += +=["Hello santa claus"]

Do you mean array += ["Hello santa clause"] ? (See my earlier
response -- actually, don't, because except for that, it probably
wasn't very good :slight_smile:

David

--
David A. Black
dblack@wobblini.net

Hi!

I would just do ('a' .. 'z').to_a.first(gets.to_i)

Call me stupid, but I don't find this function in the ruby book

HAND,
Kevin

[Bill Atkins <batkins57@gmail.com>, 2004-11-11 13.49 CET]

> array.each do |e|
> if (today_is_christmas)
> array += ["Hello"]
> retry
> end
> end
How does this work? Does 'retry' recall the method associated with its block?

Yes, and re-evaluates its arguments (if any).

Inside a method, it seems to recall the method (re-evaluating arguments)
only if the method has a block, altough you are not inside it. Didn't test
that much.

  def repeat (what, test_until)
    retry if !test_until
  end

  s = ""
  repeat(s << "x", s.length > 5)
  puts s

retry.rb:2:in `repeat': retry outside of rescue clause (LocalJumpError)
        from retry.rb:6

But:

  def repeat (what, test_until)
    retry if !test_until
  end

  s = ""
  repeat(s << "x", s.length > 5) {} # <-- note block
  puts s

#-> xxxxxx

Greetings.

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.44.0411110542180.12257-100000@wobblini...

Hi --

>
> "Kevin Börgens" <kevin@boergens.de> schrieb im Newsbeitrag
> news:2vfjurF2ljhdfU1@uni-berlin.de...
> > Hi!
> >
> >
> > How to restart a "each" iteration when the iterated array is

changed? I

> do
> > it like this
> >
> > changed=false
> > while (changed)
> > changed=false
> > array.each {|e|
> > if (today_is_christmas)
> > array=array+=["Hello santa claus"]
>
> This is sufficient:
> array += +=["Hello santa claus"]

Do you mean array += ["Hello santa clause"] ?

Well, you will have to patch the Ruby parser - but then it's sufficient.
:-))

Of course I meant to put only one "+=" there. :slight_smile: "a = a += x" is one
assignment too much.

(See my earlier
response -- actually, don't, because except for that, it probably
wasn't very good :slight_smile:

Um, which one? I can't see another post of you in this thread. Weired...

    robert

···

On Thu, 11 Nov 2004, Robert Klemme wrote:

what function? you might mean #..
in that case see 'Ranges' and 'Ranges as Sequences' topics at:
http://www.rubycentral.com/book/tut_stdtypes.html

below example might help you to understand better:

[mkhan@localhost bin]$ irb
irb(main):001:0> ('a' .. 'z')
=> "a".."z"
irb(main):002:0> ('a' .. 'z').to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
irb(main):003:0> ('a' .. 'z').to_a.first
=> "a"
irb(main):010:0> ('a' .. 'z').to_a.first(gets.to_i)
5
=> ["a", "b", "c", "d", "e"]
irb(main):010:0> ('a' .. 'z').to_a.first(gets.to_i)
3
=> ["a", "b", "c"]
irb(main):011:0>

Thanks
Mohammad

···

On Fri, 2004-11-12 at 15:03, Kevin Börgens wrote:

Hi!

>I would just do ('a' .. 'z').to_a.first(gets.to_i)
Call me stupid, but I don't find this function in the ruby book

HAND,
Kevin

--

[mkhan@localhost local]$ rm -Rf /bin/laden

Carlos wrote:

Does 'retry' recall the method associated with its block?

Yes, and re-evaluates its arguments (if any).

Inside a method, it seems to recall the method (re-evaluating arguments)
only if the method has a block, altough you are not inside it. Didn't test
that much.

Wow, this might be very powerful. Using it we can implement a custom while() without using a lambda for the condition:

def _while(condition)
   if condition then
     yield
     retry
   end
end

i = 0
_while(i < 10) { i += 1 }
i # => 10

I wonder if this is by purpose or an accidental feature. I think it would make some pretty interesting things possible if it can be relied on.

I wonder if this is by purpose or an accidental feature.

From the "ruby user guide"

···

------------------------------------------------------------
With `retry', one can define an iterator which works the same as `while',
but it's not practical due to slowness.

> def WHILE(cond)
ruby> return if not cond
ruby> yield
ruby> retry
ruby> end
nil
> i=0; WHILE(i<3) { print i; i+=1 }
012nil
------------------------------------------------------------

Guy Decoux

ts wrote:

From the "ruby user guide"

------------------------------------------------------------
With `retry', one can define an iterator which works the same as `while',
but it's not practical due to slowness.

Thank you, I have not read the Ruby User Guide (maybe I should now that I know it documents some interesting details of Ruby?) and I'm pleased about this behavior indeed being by purpose. It might be too slow for completely replacing the built-in while with it, but there might well be some interesting things it can still be used for.

I keep being amazed at how much hidden power there is in Ruby while it still remains so simple. matz really spent lots of thought about carefully selecting only the best features.