iterator

puts "express gratitude tree times"
3.times{puts "thank you!"} #Express gratitude three times
data=1,2,3
puts "print each element x of data=1,2,3"
data.each{|x| puts x} #print each element x of data
puts "compute squares of array elements[1,2,3]"
[1,2,3].map{|x| puts x*x} #computet squares of array elements
puts "compute the factorial=1 of n=3"
factorial=1
n=4
2.upto(n){|x| puts factorial *=x}


puts "iterators that don't iterate [tap]"
chars="hello world".tap{|x| puts "original object: #{x.inspect}"}
.each_char .tap{|x| puts "each_char returns: #{x.inspect}"}
.to_a .tap{|x| puts "to_a returns: #{x.inspect}"}
.map {|c| c.succ} .tap{|x| puts "map returns: #{x.inspect}"}
.sort .tap{|x| puts "sort returns: #{x.inspect}"}

iterators that don't iterate [tap]
original object: "hello world"
each_char returns: #
to_a returns: ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
map returns: ["i", "f", "m", "m", "p", "!", "x", "p", "s", "m", "e"]
sort returns: ["!", "e", "f", "i", "m", "m", "m", "p", "p", "s", "x"]


puts "012"
3.times{|x| print x}

puts "Math::PI"
0.step(Math::PI,0.1){|x| puts Math.sin(x)}


puts "\n Enumerable Object"
[1,2,3].each{|x| print x}
puts "\n"
puts "same as 1.upto(3)"
(1..3).each{|x| print x}
puts "\n the collect method the return values of the blocks into an array"
squares=[1,2,3].collect {|x| x*x}
p squares

puts "\n the select method the block returns a value other than false or nil"
evens=(1..10).select{|x| x%2==0}
p evens

#custom iterators
#This method expects a block. It generates n value of the form
#m*i+c,for i from 0..n-1, and yields them, one at a time,
#to the associated block.
puts "costom iterators"
def sequence(n,m,c)
i=0
while(i [4,7]


s="hello"
s.enum_for(:each_char).map {|c| c.suss}
#=> ["i","f","m","m","p"]

enumerator=3.times #An enumerator object
enumerator.each {|x| print x} #Prints "012"

#downto returns an enumerator with a select method
arry=10.downto(1).select {|x| x%2 ==0 } # =>[10,8,6,4,2,]
puts "\n"
p arry

#each_byte iterator returns an enumerator with a to_a method
byte_ary="hello".each_byte.to_a # => [104,101,108,108,111]
p byte_ary


iterator = 9.downto(1)
#An enumerator as external iterator
begin
#So we can use rescue below
print iterator.next while true
#Call the next method repeatedly
rescue StopIteration
#When there are no more values
puts "...blastoff!"
#An expected,nonexceptional condition
end

#an external iterator is to pass it to an internal iterator method
def iterate(iterator)
loop{yield iterator.next}
end

iterate(9.downto(1)){|x| print x}


#shows the implementation of three iterator mehods

#Call the eah method of each collection in turn.
#This is not a parallel iteration and does not require enumerators.
def sequence(*enumerables,&block)
enumerables.each do |enumerable|
enumerable.each(&block)
end
end

#Iterate the specefied collections,interleaving their elements
#This can't be done efficiently without external iterators.
#Note the use of the uncommon else clause in begin/rescue.
def interleave(*enumerables)
#Convert enumerable collections to an array of enumerators.
enumerators=enumerables.map{|e| e.to_enum}
#Loop until we don't have any more enumerators.
until enumerators.empty?
begin
e=enumerators.shift
#Take the first enumerator
yield e.next
#Get its next and pass to the block
rescue StopIteration
#If no more elements,do nothing
else
#If no exception occurred
enumerators << e
#Put the enumerator back
end
end
end

#Iterate the sqecified collections, yielding tupless of values,
#One value from each of the collections.See also Enumerable.zip.
def bundle(*enumerables)
enumerators=enumerables.map{|e| e.to_enum}
loop{yield enumerators.map {|e| e.next}
}
end

puts "\n"
#Examples of how these iterator methods work
a,b,c=[1,2,3], 4..6,'a'..'e'
sequence(a,b,c){|x| print x}
#prints "123456abcde"
puts "\n"
interleave(a,b,c) {|x| print x}
puts "\n"
#prints "14a25b36cde"
bundle(a,b,c) {|x| print x}
#'[1,4,"a"][2,5,"b"][3,6,"c"]'