Generate a sequence in Ruby - ruby

I want to take an integer from the user, and generate a sequence of five numbers starting with the given integer, and multiplying each previous number by four, using iteration. E.g., if I enter 2 then the list should be [2, 8, 32, 128, 512].
n = gets
i = 0
while i < 4
n = n * 4
p n
i = i + 1
end

I am not sure if you are looking to create an array of numbers to use later or just want to iterate. In the following you can replace puts memo with whatever you want, memo will contain the value you are looking for each pass.
s = 2
(s...(s+5)).reduce(s) do |memo, i|
puts memo
memo = memo * 4
end

Run:
(5 - 1).times.with_object([gets.to_i]){|i, a| a.push(a.last * 4)}
Input:
2
Return value:
[2, 8, 32, 128, 512]

There are a lot of ways to accomplish what you are describing. You already have some implementations in the comments and in the other answer by #Abhimanyu.
the trouble I'm having is to iterate the value for the sequence. I keep getting it as [2,2,2,2,2]
Your code example won't work because Kernel#gets doesn't return a number, but a String followed by a newline character (because it uses a default separator, from the global variable $/, which happens to be "\n"):
[1] pry(main)> gets
2
=> "2\n"
[2] pry(main)> gets.class
2
=> String
To fix your snippet you'll need to add .chomp.to_i to remove the newline and to convert it to an integer:
def generate_sequence
n = gets.chomp.to_i
i = 0
while i < 4
n = n * 4
p n
i = i + 1
end
end

Related

I don't understand this method

I'm a beginner in Ruby and I don't understand what this code is doing, could you explain it to me, please?
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
def defines a method. Methods can be used to run the same code on different values. For example, lets say you wanted to get the square of a number:
def square(n)
n * n
end
Now I can do that with different values and I don't have to repeat n * n:
square(1) # => 1
square(2) # => 4
square(3) # => 9
= is an assignment.
s = 0 basically says, behind the name s, there is now a zero.
0..n-1 - constructs a range that holds all numbers between 0 and n - 1. For example:
puts (0..3).to_a
# 0
# 1
# 2
# 3
for assigns i each consecutive value of the range. It loops through all values. So first i is 0, then 1, then ... n - 1.
s += i is a shorthand for s = s + i. In other words, increments the existing value of s by i on each iteration.
The s at the end just says that the method (remember the thing we opened with def) will give you back the value of s. In other words - the sum we accumulated so far.
There is your programming lesson in 5 minutes.
This example isn't idiomatic Ruby code even if it is syntactically valid. Ruby hardly ever uses the for construct, iterators are more flexible. This might seem strange if you come from another language background where for is the backbone of many programs.
In any case, the program breaks down to this:
# Define a method called a which takes an argument n
def a(n)
# Assign 0 to the local variable s
s = 0
# For each value i in the range 0 through n minus one...
for i in 0..n-1
# ...add that value to s.
s += i
end
# The result of this method is s, the sum of those values.
s
end
The more Ruby way of expressing this is to use times:
def a(n)
s = 0
# Repeat this block n times, and in each iteration i will represent
# a value in the range 0 to n-1 in order.
n.times do |i|
s += i
end
s
end
That's just addressing the for issue. Already the code is more readable, mind you, where it's n.times do something. The do ... end block represents a chunk of code that's used for each iteration. Ruby blocks might be a little bewildering at first but understanding them is absolutely essential to being effective in Ruby.
Taking this one step further:
def a(n)
# For each element i in the range 0 to n-1...
(0..n-1).reduce |sum, i|
# ...add i to the sum and use that as the sum in the next round.
sum + i
end
end
The reduce method is one of the simple tools in Ruby that's quite potent if used effectively. It allows you to quickly spin through lists of things and compact them down to a single value, hence the name. It's also known as inject which is just an alias for the same thing.
You can also use short-hand for this:
def a(n)
# For each element in the range 0 to n-1, combine them with +
# and return that as the result of this method.
(0..n-1).reduce(&:+)
end
Where here &:+ is shorthand for { |a,b| a + b }, just as &:x would be short for { |a,b| a.x(b) }.
As you are a beginner in Ruby, let's start from the small slices.
0..n-1 => [0, n-1]. E.g. 0..3 => 0, 1, 2, 3 => [0, 3]
for i in 0.. n-1 => this is a for loop. i traverses [0, n-1].
s += i is same as s = s + i
So. Method a(n) initializes s = 0 then in the for loop i traverse [0, n - 1] and s = s + i
At the end of this method there is an s. Ruby omits key words return. so you can see it as return s
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
is same as
def a(n)
s = 0
for i in 0..n-1
s = s + i
end
return s
end
a(4) = 0 + 1 + 2 + 3 = 6
Hope this is helpful.
The method a(n) calculates the sums of the first n natural numbers.
Example:
when n=4, then s = 0+1+2+3 = 6
Let's go symbol by symbol!
def a(n)
This is the start of a function definition, and you're defining the function a that takes a single parameter, n - all typical software stuff. Notably, you can define a function on other things, too:
foo = "foo"
def foo.bar
"bar"
end
foo.bar() # "bar"
"foo".bar # NoMethodError
Next line:
s = 0
In this line, you're both declaring the variable s, and setting it's initial value to 0. Also typical programming stuff.
Notably, the value of the entire expression; s = 0, is the value of s after the assignment:
s = 0
r = t = s += 1 # You can think: r = (t = (s += 1) )
# r and t are now 1
Next line:
for i in 0..n-1
This is starting a loop; specifically a for ... in ... loop. This one a little harder to unpack, but the entire statement is basically: "for each integer between 0 and n-1, assign that number to i and then do something". In fact, in Ruby, another way to write this line is:
(0..n-1).each do |i|
This line and your line are exactly the same.
For single line loops, you can use { and } instead of do and end:
(0..n-1).each{|i| s += i }
This line and your for loop are exactly the same.
(0..n-1) is a range. Ranges are super fun! You can use a lot of things to make up a range, particularly, time:
(Time.now..Time.new(2017, 1, 1)) # Now, until Jan 1st in 2017
You can also change the "step size", so that instead of every integer, it's, say, every 1/10:
(0..5).step(0.1).to_a # [0.0, 0.1, 0.2, ...]
Also, you can make the range exclude the last value:
(0..5).to_a # [0, 1, 2, 3, 4, 5]
(0...5).to_a # [0, 1, 2, 3, 4]
Next line!
s += i
Usually read aloud a "plus-equals". It's literally the same as: s = s + 1. AFAIK, almost every operator in Ruby can be paired up this way:
s = 5
s -= 2 # 3
s *= 4 # 12
s /= 2 # 6
s %= 4 # 2
# etc
Final lines (we'll take these as a group):
end
s
end
The "blocks" (groups of code) that are started by def and for need to be ended, that's what you're doing here.
But also!
Everything in Ruby has a value. Every expression has a value (including assignment, as you saw with line 2), and every block of code. The default value of a block is the value of the last expression in that block.
For your function, the last expression is simply s, and so the value of the expression is the value of s, after all is said and done. This is literally the same as:
return s
end
For the loop, it's weirder - it ends up being the evaluated range.
This example may make it clearer:
n = 5
s = 0
x = for i in (0..n-1)
s += i
end
# x is (0..4)
To recap, another way to write you function is:
def a(n)
s = 0
(0..n-1).each{ |i| s = s + i }
return s
end
Questions?

Check if the sum of two different numbers in an array equal a variable number?

In Ruby, I would like to take an array of numbers, select 2 different numbers, add those 2 numbers together and see weather there equal to a variable x.y'd a variable x. Here is the code I used
def arrayIsEqual? (numArray, x)
return true if numArray.sample + numArray.sample == x
return false if numArray.empty? || numArray.count == 1
end
for example
numArray = [4,2,7,5]
x = 11
arrayIsEqual (numArray, n) should return true, since 4 + 7 = n(11)
How do I get this to work?
I don't want it to be 2 random numbers, just any 2 different numbers that add up to n
It looks like you're trying to see if there are any two numbers in the array that add up to the specified value x. However, your code just picks two numbers at random and checks if those numbers add up.
Ruby has the Array#combination method, which generates all combinations of a given length:
def contains_pair_for_sum?(arr, n)
!!arr.uniq.combination(2).detect { |a, b| a + b == n }
end
A few things to note:
First, we named it according to Ruby conventions: each word is separated_by_underscores. The ? on the end means that the method is a predicate method and returns a true or false value.
Inside the method, a few things happen. Let's look at that line, piece by piece.
arr: We take the array that was passed in.
<...>.uniq: We only look at the unique elements (because the OP wants to pick two different numbers).
<...>.combination(2): We ask for all combinations from the array of length 2. If the array was [4, 5, 6], we'd get [[4, 5], [4, 6], [5, 6]].
<...>.detect { |a, b| a + b == n }: We look for the first combination that adds up to n. If we found one, that's the result of that method. Otherwise, we get nil.
!!<...>: Finally, we take the result we got from detect and negate it twice. The first negation produces a Boolean value (true if the value we got was nil, or false if it's anything else); the second negation produces a Boolean value that's identical to the truth value of the first negation. This is a Ruby idiom to coerce a result into being either true or false.
Let's see it in action:
array = [4, 5, 9, 7, 8]
contains_pair_for_sum?(array, 11)
# => true (because [4, 7] sums to 11)
contains_pair_for_sum?(array, 17)
# => true (because [9, 8] sums to 17)
contains_pair_for_sum?(array, 100)
# => false (no pair matched)
I understand that your question is "is there any pair of numbers in my array equals x", in which case this will do what you need:
def has_pair_equal?(num_array, x)
(0..num_array.length-1).any? do |i|
num_array[i+1..-1].any? { |n| n + num_array[i] == x }
end
end
This checks all sums of pairs of numbers in the array, and checks if their sum is x. sample randomly picks an item from the array, which means that what your code does is "return true sometimes if there is a pair of numbers in my array equals x"
def array_is_equal? (num_array, x)
equality = 0
num_array.each do |a|
equality += 1 if a == x
return true if equality == 2
end
return false
end
Use lowercase and underscores for variables in Ruby. The convention is different here than in some other languages.
One liner
x=[4,2,7,5]; x.each_with_index.any? {|y,i| x.each_with_index.any? {|z,j| unless i==j; z+y==11; end } }
And as a function
def pair_sum_match?(arr, x)
arr.each_with_index.any? do |y,i|
arr.each_with_index.any? do |z,j|
unless i==j
z+y==x
end
end
end
end
Updated: Added each_with_index to avoid self inclusion on checks. It's a lot longer now :-/
Just iterate over it once and use the target number to see if it matches. 100 times faster then most of the answers here
numbers = ( -10..10 ).to_a
numbers.unshift( numbers.first + -1 ) # if you do -20 or 20
numbers.push( numbers.last + 1 )
target = 5
searched = { }
matches = { }
numbers.each do |number|
if searched[ target - number + 1 ] == true
matches[ "#{ number }_plus_#{ target - number }" ] = target
end
searched[ number + 1 ] = true
end
ap matches

How do I take the sum of the digits of a square using Ruby?

I'm new to learning Ruby, and I'm trying to ask the user for an input, square that number, and then return the sum of the digits in the squared number. I'm confused when to use .to_s and .to_i, and I'd also like to accomplish this without using a shortcut.
Here's what I have so far (which doesn't work) :
def sqr_digit_sum(n)
square = (n ** 2).to_s
no_of_digits = square.size
sum = 0
i = 0
while i < no_of_digits
sum += square[i].to_i
i += 1
end
puts sum
end
I don't get why if I input 9 for a square of 81, square[0] returns 56 instead of 8. Can someone explain this?
It appears you’re using Ruby 1.8, where String#[] with a Fixnum argument (e.g. '8'[0]) returns the decimal ASCII character value. Which for '8' is 56. Since this is already a Fixnum, calling to_i on it has no effect. You should instead pass an index and length to []:
string = '81'
string[0, 1] #=> "8"
string[1, 1] #=> "1"
If you want all the characters in an array, though, you should use chars/each_char:
string = '81'
string.chars.to_a #=> ["8", "1"]
string.chars.to_a.map { |char| char.to_i } #=> [8, 1]
This makes implementing what you want fairly straightforward using the above and reduce:
n = 9
(n ** 2).to_s.chars.to_a.map { |char| char.to_i }.reduce(0, :+) #=> 9
Ultimately, though, you should upgrade to Ruby 2.0 (or at least 1.9.2+) as soon as possible as 1.8 is no longer supported and receives no security updates.
You could do this
def sqr_digit_sum(n)
square = (n ** 2)
puts square.to_s.split(//).inject(0) { |sum, number_as_string| number_as_string.to_i + sum }
end
Your code works just fine. Also, for the following code, the result is 8 as expected:
n = 9
square = (n ** 2).to_s[0]
puts square
Finally, may I suggest to refactor your code as:
def sqr_digit_sum(n)
sum = 0
(n ** 2).to_s.each_char { |c| sum += c.to_i }
puts sum
end
you don't really need a while loop there.

Hashes vs Lambdas

I found two examples that looked close to each other for finding Fibonacci numbers:
Lambda
fibonacci = ->(x){ x < 2 ? x : fibonacci[x-1] + fibonacci[x-2] }
fibonacci[6] # => 8
Hash
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
fibonacci[6] # => 8
I used both hashes and lambdas in ruby before, but not like this. This is more of a way of storing a function:
if x < 2
x
else
fibonacci[x-1] + fibonacci[x-2]
Can you explain in detail how this is working? Is this using recursion?
What are the differences between hashes like this and lambdas?
Yes it is using recursion. If we look at the code in the {}-brackets we can figure out the answer. Let's start looking at the hash. The values after new keyword is the default value. A value that will be assigned if the value does not already exist in the hash.
hash = Hash.new
p hash['new_value'] #=> nil
default_value_hash = Hash.new(0)
puts default_value_hash['new_value'] #=> 0
hash_with_block = Hash.new{|h,x| x}
puts hash_with_block['new_value'] #=> 'new_value'
So when we declare
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
we are basically saying - Create a new hash with a default value. If we ask for a number (x) smaller or equal to two, just return the input (x). Else, give us the sum of the dictionary values where the key is x-1 and x-2. Basically the Fibonacci algorithm. If x-1 and x-2 does not exist, it runs the same code again until the two basic input values are 1 and 2.
The difference between the two approaches is that the hash saves the values (in a hash...). This can be a huge advantage in some cases. Every time the lambda is called it needs to recalculate the values for all numbers below the called value.
# Let's create a counter to keep track of the number of time the lambda is called.
# Please do not use global variables in real code. I am just lazy here.
#lambda_counter = 0
fibonacci_lambda = ->(x){
#lambda_counter += 1
x < 2 ? x : fibonacci_lambda[x-1] + fibonacci_lambda[x-2]
}
p (1..20).map{|x| fibonacci_lambda[x]}
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
p #lambda_counter # => 57290
# lambda called 57290 times!
#hash_counter = 0
fibonacci_hash = Hash.new{ |h,x|
#hash_counter += 1
h[x] = x < 2 ? x : h[x-1] + h[x-2]
}
p (1..20).map{|x| fibonacci_hash[x]}
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
p #hash_counter # => 21
# Only called 21 times!
The reason for the big difference in calls is the nature of recursion. The lambda does not store its values and when the value for 10 is calculated it recalculates the value for 3 more than 20 times. In the hash this value can be stored and saved for later.
In the first case, you are defining a recursion which will be called recursively.
In the case of the hash, the values will also be computed recursively, but stored and then access for giving the result.
Lambda
fibonacci = ->(x){ x < 2 ? x : fibonacci[x-1] + fibonacci[x-2] }
fibonacci[6]
fibonacci # => <Proc:0x2d026a0#(irb):5 (lambda)>
Hash
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
fibonacci[6]
fibonacci # => {1=>1, 0=>0, 2=>1, 3=>2, 4=>3, 5=>5, 6=>8}
In one case, you are not leaving any footprint in memory, whereas the hash will continue to keep the computed value. So it depends on what you need.
If you need to access fibonacci[6] one more time, the lambda will recompute the result, whereas the hash will give you the result immediately without redo the calculations.
What are the differences between hashes like this and lambdas?
lambdas and hashes have nothing in common. Your question is like asking:
What are the differences between methods and arrays?
It's just that Hashes can specify a default value for a non-existent key:
h = Hash.new(10)
h["a"] = 2
puts h["a"]
puts h["b"]
--output:--
2
10
Hashes also provide a way to dynamically specify the default value: you can provide a block. Here is an example:
h = Hash.new do |h, key|
h[key] = key.length
end
puts h['hello']
puts h['hi']
p h
--output:--
5
2
{"hello"=>5, "hi"=>2}
When you access a non-existent key, the block is called, and the block can do whatever you want. So someone cleverly figured out that you could create a hash and specify a default value that calculated fibonacci numbers. Here is how it works:
h = Hash.new do |h, key|
if key < 2
h[key] = key
else
h[key] = h[key-1] + h[key-2]
end
end
That creates the Hash h, which is a Hash with no keys or values. If you then write:
puts h[3]
...3 is a non-existent key, so the block is called with the args h and 3. The else clause in the block executes, which gives you:
h[3-1] + h[3-2]
or:
h[2] + h[1]
But to evaluate that statement, ruby has to first evaluate h[2]. But when ruby looks up h[2] in the hash, the key 2 is a non-existent key, so the block is called with the args h and 2, giving you:
(h[2-1] + h[2-2]) + h[1]
or:
(h[1] + h[0]) + h[1]
To evaluate that statement, ruby first has to evaluate the first h[1], and when ruby tries to look up h[1] in the hash, 1 is a non existent key, so the block is called with the args h and 1. This time the if branch executes, causing this to happen:
h[1] = 1
and 1 is returned as the value of h[1], giving you this:
(1 + h[0]) + h[1]
Then ruby looks up h[0], and because 0 is a non-existent key, the block is called with the args h and 0, and the if clause executes and does this:
h[0] = 0
and 0 is returned as the value of h[0], giving you this:
(1 + 0) + h[1]
Then ruby looks up h[1] in the hash, and this time the key 1 exists, and it has a value of 1, giving you:
(1 + 0) + 1
And that is equal to 2, so h[3] is set equal to 2. After calling h[3], you get this output:
puts h[3]
p h
--output:--
2
{1=>1, 0=>0, 2=>1, 3=>2}
As you can see, the previous calculations are all cached in the hash, which means that those calculations don't have to be performed again for other fibonacci numbers.

Ruby Enumeration: Taken first n where block returns true

I want to take the first "n" entries which pass the block
a = 1..100_000_000 # Basically a long array
# This iterates over the whole array -- no good
b = a.select{|x| x.expensive_operation?}.take(n)
I want to short circuit the iteration once i've got n entries where 'expensive' condition is true.
What do you suggest? take_while and keep count of n?
# This is the code i have; which i think can be written better, but how?
a = 1..100_000_000 # Basically a long array
n = 20
i = 0
b = a.take_while do |x|
((i < n) && (x.expensive_operation?)).tap do |r|
i += 1
end
end
Ruby 2.0 implements lazy enumerables, for older versions use the gem enumerable-lazy:
require 'enumerable/lazy'
(1..Float::INFINITY).lazy.select(&:even?).take(5).to_a
#=> [2, 4, 6, 8, 10]
It should work with a simple for loop and a break :
a = 1..100_000_000 # Basically a long array
n = 20
selected = []
for x in a
selected << x if x.expensive_operation?
break if select.length == n
end

Resources