How does yield work with a block in Ruby? [duplicate] - ruby

This question already has answers here:
Blocks and yields in Ruby
(10 answers)
Closed 8 years ago.
I'm trying to understand how yield works in Ruby?
def ablock
i = 1
j = 2
yield(i, j, 3, 4)
end
ablock do |x| puts x
end
This gives me an output of -
1
2
3
4
But,
def ablock
i = 1
j = 2
yield(i, j, 3, 4)
end
ablock do |x,y| puts x, y
end
Gives me only
1
2
as the output. Why don't 3 & 4 print?

The answer is pretty simple. You have defined your block method correctly but when you go to give it a code block you only give it one variable to hold 4 objects. Instead, try giving it a variable for each object you are yielding!
def ablock
i=1
j=2
yield(i,j,3,4)
end
ablock do |i,j,k,l|
puts i
puts j
puts k
puts l
end
If you would only like to use one variable in your code block you have to do multiple yield statements(one for each object).
def ablock
i=1
j=2
yield(i)
yield(j)
yield(3)
yield(4)
end
ablock do |i|
puts i
end
Happy coding!

Related

How to multiply integer digits between them?

I want to my n to multiply with next number for example if n=99 i want it to 9*9 and then return a result, and then i want the result (9*9 = 81 then 8*1 = 8) to multiply until it becomes 1 digit.
Here's my code:
def persistence(n)
if n <= 9
puts n
else
n.to_s.each_char do |a|
a.to_i * a.to_i unless n < 9
puts a.to_i
end
end
end
and i want it to return this:
persistence(39) # returns 3, because 3*9=27, 2*7=14, 1*4=4
# and 4 has only one digit
persistence(999) # returns 4, because 9*9*9=729, 7*2*9=126,
# 1*2*6=12, and finally 1*2=2
persistence(4) # returns 0, because 4 is already a one-digit number
def persistence(n)
i = 0
while n.to_s.length != 1
n = n.to_s.each_char.map(&:to_i).reduce(:*)
i +=1
end
i
end
persistence(39) #=> 3
persistence(999) #=> 4
Other version:
def p(n, acc)
return acc if n <= 9
p(n.to_s.each_char.map(&:to_i).reduce(:*), acc+1)
end
def persistence(n)
p(n, 0)
end
I will leave the breaking down of method and understanding what's happening and what is the difference b/w two variations to you. Will love to see your comment explaining it.
def persistence(n)
0.step.each do |i|
break i if n < 10
n = n.digits.reduce(:*)
end
end
persistence 4 #=> 0
persistence 39 #=> 3
persistence 999 #=> 4
persistence 123456789123456789 #=> 2
Regarding the last result, note that 2*5*2*5 #=> 100.

How to calculate factorial in ruby [duplicate]

This question already has answers here:
Ruby factorial function
(20 answers)
Closed 8 years ago.
QUESTION :
Input:
4 # number of input
1
2
4
3
Output:
1
2
24
6
CANNOT GET DESIRED OUTPUT
My code:
num = Integer(gets.chomp)
k = []
for i in 1..num
k[i] = Integer(gets.chomp)
end
k.each do |w|
for i in 1..w
w.to_i = w*i
end
puts w
end
To get factorial of n
(1..n).inject :*
To take care of zero
(1..n).inject(1, :*)
you can try like:
input = Integer(gets.chomp)
ans = 1
for i in 1..input
ans = ans*i
end
print(ans)

Problems with Modulo operator Ruby: Why am I getting "undefined method `%' for 1..100:Range"?

For some reason I'm getting the error undefined method '%' for 1..100:Range when I run the following code:
[1..100].each do |x|
if x % 3 == 0 && x % 5 == 0
puts "CracklePop"
elsif x % 3 == 0
puts "Crackle"
elsif x % 5 == 0
puts "Pop"
else
puts x
end
end
Any idea what's going on? Any help is much appreciated.
That's the wrong syntax for ranges.
You've made an array with 1 element, and that element is itself the range 1..100. What you've written is equivalent to [(1.100)]. You're iterating over the outer array one time, and setting x to (1..100)
You want (1..100).each, which invokes each on the range, not on an array containing the range.
By doing [1..100] you are not looping from 1 to 100 but on 1..100, which is a Range object, what you really want to do is:-
(1..100).step do |x|
if x % 3 == 0 && x % 5 == 0
puts "CracklePop"
elsif x % 3 == 0
puts "Crackle"
elsif x % 5 == 0
puts "Pop"
else
puts x
end
end
Basically, Range represents an interval, you can iterate over Range as explained here, create an array from Range as explained here and more details on range can be found here.
Just as it says. 1..100 does not have a method %. The expression (1..100) % 3 is undefined.

Ruby stop and move to next iteration of for loop

I have a for loop with an if elsif statement inside. On the first if, if the condition is met I want it to stop there and go on to the next iteration of the loop.
This is a very simplified version of what I am trying to do:
array = [1,2,3,4,"x"]
for i in 0..(array.count -1)
if array[i] == "x"
#start next for loop iteration without executing the elsif
elsif array[i] < 3
puts "YAY!"
end
end
What I am exactly trying to do is iterating through an array which all but one of the elements are integers but one of them is a string. On the string element, I need the loop (whatever kind is best) to skip the rest of the code and go to the next iteration of the loop. This is important because the second if statement uses an 'array_element < 11 condition' so if it runs that on the string element I get "comparison of String with 11 failed"
so I would want arr[x][3] this is what i tried but it gives me 8 8 8 8 instead of a single 8.
arr = [[1,2,3,"4"], [5,6,7,8], [9,10,11,12]]
arr.each{|x|
x.each {|i|
next if x[3].instance_of? String
if x[3] < 12 puts x[3]
end
}
}
Ok this works!! Thank you iAmRubuuu!!
arr = [1,2,3,"4"], [5,6,7,8], [9,10,11,12], [13,14,15,"16"], [17,18,19,20]]
arr.each_with_index{|x, i|
next if x.last.instance_of? String
if x.last < 21
puts x.last
end
}
give me the output
8
12
20
Don't use for in, use each.
(0..10).each do |i|
next if i == 5
if i == 10
puts "YAY!"
end
end
As per your edit, hope the below one you are looking for:
arr = [1, 2, 3, "11", 11]
arr.each do |x|
next if x.instance_of? String
puts "#{x} is #{x.class}"
end
Output:
1 is Fixnum
2 is Fixnum
3 is Fixnum
11 is Fixnum
EDIT
Code:
arr = [[1,2,3,"4"], [4,5,6,7], [8,9,10,11]]
arr.each{|x|
x.each{ |i|
next if i.instance_of? String
puts "#{i} is #{i.class}"
}
}
Output:
1 is Fixnum
2 is Fixnum
3 is Fixnum
4 is Fixnum
5 is Fixnum
6 is Fixnum
7 is Fixnum
8 is Fixnum
9 is Fixnum
10 is Fixnum
11 is Fixnum
V_1(from your first comment in my answer post)
arr = [[1,2,3,"4"], [4,5,6,7], [8,9,10,11]]
puts arr[1].last,arr.last.last
Output:
7
11
V_2(from your first comment in my answer post)
arr = [[1,2,3,"4"], [4,5,6,7], [8,9,10,11]]
arr.each_with_index{ |x,i|
next if i == 0
#p x,i
p "last element of inner array:#{x.last}"
}
Output:
"last element of inner array:7"
"last element of inner array:11"

Start a loop from 1

I recently came upon the scary idea that Integer.count loops in Ruby start from 0 and go to n-1 while playing with the Facebook Engineering puzzlers. I did the dirty fix of adding one to the block variable in the beginning so that it would start at one instead.
Is there a prettier way?
Example:
10.times do |n|
n += 1
puts n
end #=> 012345789
Ruby supports a number of ways of counting and looping:
1.upto(10) do |i|
puts i
end
>> 1.upto(10) do |i|
> puts i
| end #=> 1
1
2
3
4
5
6
7
8
9
10
There's also step instead of upto which allows you to increment by a step value:
>> 1.step(10,2) { |i| puts i } #=> 1
1
3
5
7
9
You could use a range:
(1..10).each { |i| puts i }
Ranges give you full control over the starting and ending indexes (as long as you want to go from a lower value to a higher value).
Try
(1..10).each do |i|
# ... i goes from 1 to 10
end
instead. It is also easier to read when the value of i matters.
Old, but this might be something somebody's lookin for..
5.times.with_index(100){|i, idx| p i, idx};nil
#=>
0
100
1
101
2
102
3
103
4
104
There is of course the while-loop:
i = 1
while i<=10 do
print "#{i} "
i += 1
end
# Outputs: 1 2 3 4 5 6 7 8 9 10

Resources