array.each restart when array is changed

K

Kevin Börgens

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
 
K

Kevin Börgens

Kevin said:
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
 
A

Ara.T.Howard

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

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
--
===============================================================================
| 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
===============================================================================
 
S

Shashank Date

Kevin said:
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}
 
T

Tim Hunter

Kevin said:
#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>
 
R

Robert Klemme

Shashank Date said:
Kevin said:
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
 
C

Carlos

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.

--
 
B

Bill Atkins

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

Bill
 
R

Robert Klemme

Kevin Börgens said:
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
 
F

Florian Gross

Kevin said:
#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)
 
C

Carlos

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.
 
D

David A. Black

Hi --

Kevin Börgens said:
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 :)


David
 
F

Florian Gross

Carlos said:
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.
 
T

ts

F> 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.

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




Guy Decoux
 
F

Florian Gross

ts said:
From the "ruby user guide"

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.
 
R

Robert Klemme

David A. Black said:
Hi --

Kevin Börgens said:
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. :) "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 :)

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

robert
 
M

Mohammad Khan

Hi!

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

HAND,
Kevin

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top