Related
I'm a new web developer and need assistance generating a given output to a problem:
def fib(n)
if (n<=2)
return 1
else
return (fib(n-1)+fib(n-2))
end
end
puts "Enter the number of terms:-"
n=gets.chomp.to_i
puts "The first #{n} terms of fibonnaci series are:-"
for c in 1..n
puts fib(c)
end
OUTPUT:
Enter the number of terms:-
5
The first 5 terms of fibonnaci series are:-
1
1
2
3
5
Excepted output:
1
22
333
55555
88888888
How would I be able to make my code produce the target output?
You just need to iterate through the range and calculate fibonacci for every member and you can multuply string with *
def fibonacci(n)
return n if (0..1).include?(n)
fibonacci(n - 1) + fibonacci(n - 2)
end
def print_pyramide(n)
(2..(n + 1)).each do |i|
fib = fibonacci(i)
puts fib.to_s * fib
end
end
print_pyramide(2)
# will print
# 1
# 22
print_pyramide(5)
# will print
# 1
# 22
# 333
# 55555
# 88888888
You could use Enumerator::produce, which made it's debut in Ruby v2.7.
Enumerator.produce([1, 1]) { |n1, n2| [n2, n1 + n2] }
.with_index(1)
.take(5)
.each { |(_,f),i| puts f.to_s * i }
prints
1
22
333
5555
88888
Note:
enum = Enumerator.produce([1, 1]) { |n1, n2| [n2, n1 + n2] }
#<Enumerator: #<Enumerator::Producer:0x00007fb18084de18>:each>
enum.next #=> [1, 1]
enum.next #=> [1, 2]
enum.next #=> [2, 3]
enum.next #=> [3, 5]
enum.next #=> [5, 8]
I have a method which returns finds out which one of the given numbers differs from the others in evenness and returns the index of it (+1).
def iq_test(numbers)
new_array = numbers.split(" ").collect {|n| n.to_i}
x = new_array.select(&:even?)
y = new_array.select(&:odd?)
if x.count > y.count
new_array.split.each_with_index do |value, index|
"#{index + 1}".to_i if value % 3 != 0
else y.count > x.count
"#{index + 1}".to_i if value % 2 == 0
end
end
end
For example iq_test("2 4 7 8 10") should return 3.
However, I am receiving
syntax error, unexpected keyword_else, expecting keyword_end
and I can't find out where I am not closing some code off.
This is going to be part code review as well as answer. Let's start with the first part:
new_array = numbers.split(" ").collect {|n| n.to_i}
x = new_array.select(&:even?)
y = new_array.select(&:odd?)
Spend time to think of good variable names. I wouldn't use "new_array" as a variable name, because it doesn't provide any clue as to what it contains. Do this kind of thing too many times, and a program becomes incomprehensible.
x and y are really evens and odds, aren't they? Those would be better variable names.
A common Ruby idiom is to use plural names for arrays, singular names for everything else.
The split by default splits on whitespace, so the (" ") is unnecessary.
Be careful with indentation.
Your selects are fine, however there is a shortcut: Enumerable's partition.
This is really my own style, but I use map when processing all values in an array, and collect only when doing something like extracting attributes from an array of objects. (In other words, I use map much more often).
note that (&:to_i) is a bit of a shortcut for {|n| n.to_i}
Rewritten considering the above, this part might look like this:
numbers = input.split.map(&:to_i)
evens, odds = numbers.partition(&:even?)
Now let's look at the rest:
if x.count > y.count
new_array.split.each_with_index do |value, index|
"#{index + 1}".to_i if value % 3 != 0
else y.count > x.count
"#{index + 1}".to_i if value % 2 == 0
end
end
And let's consider the error message you got: unexpected keyword else; expected end. This has everything you need to know to answer the question (and you'll find that most error messages do, if you think about them). It says it found an else where it expected an end. And that's exactly the problem, you need to put end before the else to close the do/end block. Also, your else part is missing your iteration logic.
Other notes:
Again, be careful with indentation. Your ends do not line up with what they're ending. Proper alignment can help catch these kinds of errors. Use of an IDE like Rubymine or a sophisticated text editor with Ruby support can help as well.
else clauses are standalone, you don't put a condition after them. Perhaps you meant elsif as Holger commented.
Using string interpolation ("#{}") converts expressions to a string. Here you're converting index + 1 to a string, and then back to an integer with .to_i which cancels it out, so to speak. Simply index + 1 will do.
Array#index can be used to determine the index of a value.
It's not clear if you want all indices in case there is more than one.
Here's a version considering the above:
if evens.count > odds.count
odds.map{|n| numbers.index(n) + 1}
elsif odds.count > evens.count
evens.map{|n| numbers.index(n) + 1}
end
If you like this kind of thing, bring your working code to http://codereview.stackexchange.com/!
This specific error is because you do not have a closing end for your each_with_index block. To fix this error you need:
def iq_test(numbers)
new_array = numbers.split(" ").collect {|n| n.to_i}
x = new_array.select(&:even?)
y = new_array.select(&:odd?)
if x.count > y.count
new_array.split.each_with_index do |value, index|
"#{index + 1}".to_i if value % 3 != 0
end #end of block
elsif y.count > x.count #in order for this to have a condition, it must be an elsif
"#{index + 1}".to_i if value % 2 == 0
end #end of if statement
#end - remove this extra end
end #end of function
Code
def odd_one_out(str)
evens, odds = str.split.partition { |s| s.to_i.even? }
case [evens.size <=> 1, odds.size <=> 1]
when [0, 1] then evens.first
when [1, 0] then odds.first
else nil
end
end
Examples
odd_one_out "0 3 4 6" #=> "3"
odd_one_out "1 5 7 8" #=> "8"
odd_one_out "0 2 4 6" #=> nil
odd_one_out "1 5 7 9" #=> nil
odd_one_out "0 2 3 5" #=> nil
odd_one_out "3" #=> nil
odd_one_out "8" #=> nil
odd_one_out "" #=> nil
Explanation
See Integer#<=>.
Suppose
str = "0 3 4 6"
then
a = str.split
#=> ["0", "3", "4", "6"]
evens, odds = a.partition { |s| s.to_i.even? }
#=> [["0", "4", "6"], ["3"]]
evens
#=> ["0", "4", "6"]
odds
#=> ["3"]
b = [evens.size <=> 1, odds.size <=> 1]
#=> [1, 0]
b == [0, 1]
#=> false
b == [1, 0]
#=> true
c = odds.first
#=> "3"
The case statement, and therefore the method, returns "3".
I've seen solutions posted in other languages but not Ruby so I'm asking here.
Trying to find out the largest prime factor of 13195.
My code is as follows
# find out all numbers that divide without remainder into 13195
array = []
count = 2
13195.times do
if 13195 % count == 0
array.push(count)
end
count += 1
end
#From those numbers that divide cleanly into 13195, find out which are prime aka can only be divided by themselves and 1
new_count = 2
primes = 0
array.each do |x|
while new_count < x
if x % new_count != 0
else
if x > primes
primes = x
end
end
new_count += 1
end
end
puts primes
In my first loop I am populating an empty array with all the numbers that divide into 13195 without a remainder, from testing this piece of code seems to be working.
It's the second part of my solution that's the problem inside my each statement, can someone point me in the right direction?
I suggest you use Prime#prime_division:
require 'prime'
def largest_prime_factor(n)
Prime.prime_division(n).max_by(&:first).first
end
largest_prime_factor(13195)
#=> 29
(1..1000).to_a.sample(15).sort.each {|n| puts "%3d: %3d" % [n, largest_prime_factor(n)]}
61: 61
80: 5
88: 11
250: 5
304: 19
414: 23
514: 257
548: 137
679: 97
716: 179
754: 29
770: 11
906: 151
907: 907
968: 11
For example,
n = 13195
a = Prime.prime_division(n)
#=> [[5, 1], [7, 1], [13, 1], [29, 1]]
b = a.max_by(&:first)
#=> [29, 1]
b.first
#=> 29
It appears that the elements of the array returned by prime_division are in order of increasing prime factor. If that were guaranteed, one could just write:
Prime.prime_division(n).last.first
I used max_by in the event that the order of those elements is implementation-specific.
Shorter version:
require 'prime'
primes = Prime.each(13195).to_a
upper = primes.last
primes will have all primes from 0 to 13195 and upper obviously the last.
I set a limit of prime numbers to 100000 (to avoid of couple days of calculation of big numbers like 600851475143 =) )
def prime_factors(n)
prime_array = []
p = 2
if n < 2
return p
end
while p < n && p < 1000000
if n % p == 0
prime_array.push(p)
end
p +=1
end
primes = []
prime_array.size.times do |i|
if n > 1
n = n / prime_array[i]
primes.push(prime_array[i])
end
end
return primes.last
end
#prime_factors(600851475143)
puts prime_factors(600851475143)
#prime_factors(13195)
puts prime_factors(13195)
Another way to use prime_division:
require 'prime'
(13195).prime_division.map(&:first).max
=> 29
Your second loop can be re-written to do what is meant to do.
As I understand, your goal is to select from array, largest of such elements that are prime (divides by only 1 and itself). In other words, an element x is eligible if it is not divisible by any number between 2 and x-1.
result = array.select {|x| not (2..x-1).any? {|i| x % i == 0} }.max
#=> 29
Currently, your logic has some flaws. It is not resetting the value of new_count and hence you are getting wrong results. Here is corrected version:
array.each do |x|
is_prime = true
while new_count < x
if x % new_count == 0
is_prime = false
end
new_count += 1
end
new_count = 2
primes = x if is_prime and x > primes
end
Without using Prime#prime_division we can dived the problems into small parts. the first part if to write a method that determine whether a number if prime or not, which can be like :
def prime?(num)
if num < 2
return false
end
(2...num).each do |ele|
if num % ele == 0
return false
end
end
return true
end
then we can write our main method which is asking for the prime_factors of a number like:
def prime_factors(num)
prime_facts = []
(1..num).each do |i|
if num % i == 0 && prime?(i)
prime_facts << i
end
end
return prime_facts
end
print prime_factors(24) #=> [2, 3]
puts
print prime_factors(60) #=> [2, 3, 5]
puts
print prime_factors(13195) # [5, 7, 13, 29]
puts
I'm running through TestFirstRuby and I've been stuck on problem 12, building a Reverse Polish Notation calculator. I've gotten through all of the tests except for the last one, asking me to take a string ("1 2 3 * +" and then "1 2 3 * + 4 5 / -"), and then evaluate the expression.
What I'm trying to do is convert the string to an array, changing the numbers into integers and the operators into symbols, then go through the array and evaluate the expression anytime it comes to an operator.
Here's the relevant part of the code:
def initialize
#expression = ''
end
def tokens(string)
tokens = string.split(' ')
tokens.map! { |digit| /[0-9]/.match(digit) ? digit.to_i : digit.to_sym }
end
def evaluate(string)
#1 2 3 * +
#1 2 3 * + 4 5 - /
total = 0
#expression = tokens(string)
#expression.map!{|item|
index = #expression.index(item)
if item == :+
total = total + (#expression[index-1] + #expression[index-2])
2.times {#expression.delete_at(index-1)}
elsif item == :-
total = total + (#expression[index-1] - #expression[index-2])
2.times {#expression.delete_at(index-1)}
elsif item == :x
total = total + (#expression[index-1] * #expression[index-2])
2.times {#expression.delete_at(index-1)}
elsif item == :/
total = total + (#expression[index-1].to_f / #expression[index-2])
2.times {#expression.delete_at(index-1)}
end
}
total
end
What I WANT to happen is this: for each item in the array, it checks if it matches any of the symbols. If there's a match, it changes the element two spaces back from the symbol into the value of whatever the expression is (so 2 3 * becomes 5 3 *). Then, I"m trying to delete the operator and the integer immediately before it, leaving only the evaluated value. I'm doing this by running delete_at twice on the index just before the operator (ideally, 5 3 * goes to 5 * and then just 5). Then it'll move on to the next element in the array.
What I THINK is going wrong, and am having trouble fixing: I think something's going on with the variable scope here. I'm trying to get the expression to be permanently changed every time it runs the code on whatever element it's currently on in the each loop. For each element, a variable 'index' is set using #expression.index(item). This should reset for each element in the each loop. I THINK what's going on is that the original #expression array is being called on for each iteration of the each loop, unchanged from each iteration of the each loop.
The error I'm getting is saying that when it gets to the '+' at the end of the first test string ('1 2 3 * +'), it's trying to add using :x, meaning that when it's calling for the two variables to add together (#expression[index-1] + #expression[index-2]), it's pulling the symbol, which I thought should have been deleted from #expression already. So what I'm hoping will evaluate as 6 + 1 is being evaluated as 3 + :x, which wouldn't work. It's pulling elements from the original array, instead of pulling from the array as it's changed.
Hopefully I'm explaining this clearly enough. Any advice would be great. I'm thinking there's something with scope going on, but I can't find anything specific to this kind of problem to help me out. I've tried different ways of coding this (.map, .each_with_index, .map.with_index, and others), and I'm getting the same problem each time.
You have a tremendous amount of redundant code. In particular, you replicate the operations for each of the four operators. Here is a more Ruby-like way of implementing your calculator.
Code
def evaluate(string)
arr = create_arr(string)
until arr.size == 1
i = arr.index(arr.find { |e| e.is_a? Symbol })
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
arr.delete_at(i)
arr.delete_at(i-1)
end
arr.first
end
def create_arr(string)
string.split(/\s+/).map { |e| e =~ /-?[0-9]+/ ? e.to_i : e.to_sym }
end
The line in create_arr could alternatively end : e } (sent accepts a string or symbol for the method), in which case e.is_a? Symbol would be changed to e.is_a? String.
Examples
evaluate("3 4 * 2 / 3 - 2 *") #=> 6
evaluate("10 2 / 3 + 2 / 2 -") #=> 2
evaluate("8 -2 / 1 +") #=> -3
evaluate("5 1 2 + 4 * + 3 -") #=> 14
Explanation
Suppose
string = "2 3 4 * 2 / +"
Step 1
arr = create_arr(string) #=> [2, 3, 4, :*, 2, :/, :+]
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :*
i = arr.index(v) #=> 3
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[1] = arr[1].send(arr[3], arr[2])
# arr[1] = 3.send(:*, 4) #=> 12
arr #=> [2, 12, 4, :*, 2, :/, :+]
arr.delete_at(i) #=> :*
arr #=> [2, 12, 4, 2, :/, :+]
arr.delete_at(i-1) #=> 4
arr #=> [2, 12, 2, :/, :+]
Step 2
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :/
i = arr.index(v) #=> 3
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[1] = arr[1].send(arr[3], arr[2])
# arr[1] = 12.send(:/, 2) #=> 6
arr #=> [2, 6, 2, :/, :+]
arr.delete_at(i) #=> :/
arr #=> [2, 6, 2, :+]
arr.delete_at(i-1) #=> 2
arr #=> [2, 6, :+]
Step 3
arr.size == 1 #=> false
v = arr.find { |e| e.is_a? Symbol } #=> :+
i = arr.index(v) #=> 2
arr[i-2] = arr[i-2].send(arr[i], arr[i-1])
# arr[0] = arr[0].send(arr[2], arr[1])
# arr[0] = 2.send(:+, 6) #=> 8
arr #=> [8, 6, :+]
arr.delete_at(i) #=> :+
arr #=> [8, 6]
arr.delete_at(i-1) #=> 6
arr #=> [8]
Step 4
arr.size == 1 #=> true
arr.first #=> 8
I've been going at this problem for a few hours, and I can't see why I can't get it to run properly. The end game to this method is having 2 numbers in an array equaling zero when added together. Here is my code:
def two_sums(nums)
i = 0
j = -1
while i < nums.count
num_1 = nums[i]
while j < nums.count
num_2 = nums[j]
if num_1 + num_2 == 0
return "There are 2 numbers that sum to zero & they are #{num_1} and #{num_2}."
else
return "Nothing adds to zero."
end
end
i += 1
j -= 1
end
end
The problem I'm having is unless the first and last number in the array are the positive and negative of the same number, this will always return false.
For example, if I had an array that was [1, 4, 6, -1, 10], it should come back true. I'm sure my 2 while statement is the cause of this, but I can't think of a way to fix it. If someone could point me in the right direction, that would be helpful.
You can find the first pair that adds up to 0 like this:
nums.combination(2).find { |x, y| x + y == 0 }
#=> returns the first matching pair or nil
Or if you want to select all pairs that add up to 0:
nums.combination(2).select { |x, y| x + y == 0 }
#=> returns all matching pairs or an empty array
Therefore you can implement your method like this:
def two_sums(nums)
pair = nums.combination(2).find { |x, y| x + y == 0 }
if pair
"There are 2 numbers that sum to zero & they are #{pair.first} and #{pair.last}."
else
"Nothing adds to zero."
end
end
Or if you want to find all pairs:
def two_sums(nums)
pairs = nums.combination(2).select { |x, y| x + y == 0 }
if pairs.empty?
"Nothing adds to zero."
else
"The following pairs sum to zero: #{pairs}..."
end
end
Here's another way:
Code
def sum_to_zero(arr)
arr.group_by { |e| e.abs }
.values
.select { |a| (a.size > 1 && a.first == 0) || a.uniq.size > 1 }
end
Examples
sum_to_zero [1, 4, 6, -1, 10] #=> [[1, -1]]
sum_to_zero [1, 4, 1, -2, 10] #=> []
sum_to_zero [1, 0, 4, 1, 0, -1] #=> [[1, 1, -1], [0, 0]]
This method is relatively fast. Let's try it with an array of 200,000 elements, each a random number between -500,000 and 500,000.
require 'time'
t = Time.now
arr = Array.new(200_000) { rand(1_000_001) - 500_000 }
arr.size #=> 200000
sum_to_zero(arr).size #=> 16439
Time.now - t
#=> 0.23 (seconds)
sum_to_zero(arr).first(6)
#=> [[-98747, 98747],
# [157848, -157848],
# [-459650, 459650],
# [176655, 176655, -176655],
# [282101, -282101],
# [100886, 100886, -100886]]
If you wish to group the non-negative and negative values that sum to zero:
sum_to_zero(arr).map { |a| a.partition { |e| e >= 0 } }.first(6)
#=> [[[98747], [-98747]],
# [[157848], [-157848]],
# [[459650], [-459650]],
# [[176655, 176655], [-176655]],
# [[282101], [-282101]],
# [[100886, 100886], [-100886]]]
If you only want a single value for each group (a non-negative value, say):
sum_to_zero(arr).map { |a| a.first.abs }.first(6)
#=> [98747, 157848, 459650, 176655, 282101, 100886]
I think the most Ruby way would be:
nums.combination(2).any? { |x,y| (x+y).zero? }
Here's a way that should work well for large arrays. The methods above which go through every possible combination of two numbers are perfectly fine for small cases but will be very slow and memory hungry for arrays with lots of elements.
def two_sums nums
h = Hash.new
nums.each do |n|
return true if h[-n]
h[n] = true
end
false
end
Well, given it's tagged as #ruby, here's the most "ruby way" I could think of tackling this problem:
def two_sums(arr)
numbers = arr.combination(2).select { |a| a.reduce(:+) == 0 }.flatten
if numbers.empty?
"Nothing adds to zero."
else
"There are 2 numbers that sum to zero & they are #{numbers.first} and #{numbers.last}."
end
end
array.combination(2).select{|x|x[0] + x[1] == 0}