Random number generator issues in Ruby - ruby

My intention here is just to fill up an array with numbers in order from 1, to a random number between 1 and 1000. However, after repeatedly running this code (about 50 times), the highest number I have gotten is 120, and only twice has it been over 100. The majority of my arrays were anywhere between 0 and 60. This behavior appears off to me. Am I doing something wrong?
my_array = []
i = 0
while i <= rand(1000)
my_array << i
i += 1
end
puts my_array.count
puts my_array

Your function is broken, because you're checking versus the random number. Do this:
(0..1000).collect{ rand(1000) }
This will return an array of one thousand random numbers.
Or, closer to your code:
my_array = []
i = 0
while i <= 1000
my_array << rand(1000)
i += 1
end
As per comment, what you want is:
(1..rand(1000))
(1..rand(1000)).to_a
The first results in a range, which is "easier to carry around", the second results in the populated array.
(Edit) Note:
(1..10) is inclusive - (1..10).to_a == [1,2,3,4,5,6,7,8,9,10]
(1...10) is partially exclusive - (1...10).to_a == [1,2,3,4,5,6,7,8,9] - it does not include the end of the array, but still includes the beginning.

It sounds like you want:
(1...rand(1000)).to_a

Additionally, I have amended my code to reflect what I was trying to accomplish initially. My problem was that every time I looped through my code I generated a new random number. Because of this, as 'i' incremented toward 1000 it became more and more likely that a random number would be generated that was lower than 'i'. My fix, while not as elegant as the solution above that I accepted, was to store the random number in a variable, BEFORE attempting to use it in a loop. Thanks again. Here is the amended code:
my_array = []
i = 0
g = rand(1000)
while i <= g
my_array << i
i += 1
end
puts my_array.count
puts my_array

Related

Find the odd int - Ruby Nested Loop Error

I was doing this question on codewars: "Given an array, find the int that appears an odd number of times. There will always be only one integer that appears an odd number of times."
Code:
def find_it(seq)
int = []
for a in seq do
count = 0
for b in seq do
if a == b
count += 1
end
end
if count % 2.0 != 0
int << b
end
end
puts int.uniq[0].to_i
end
It was tested against a couple inputs, but the answers were wrong for these two arrays:
find_it([1,1,2,-2,5,2,4,4,-1,-2,5]) - returns 5 instead of -1
find_it([1,1,1,1,1,1,10,1,1,1,1]) - returns 1 instead of 10
What went wrong with my code?
if count % 2.0 != 0
int << b
end
The problem you have here is that your pushing b instead of a into the integer array, so what's happening is that instead of the value that you counted being pushed in, your pushing in the last value of b which is the last value element in the array regardless as long as the condition that the counter is an odd number, although b and counter have nothing to do with each other. so to fix it you replace b with a so that it pushes in the value you are testing comparing with the other elements in the second loop
fix:
if count % 2.0 != 0
int << a
end
a similar yet simpler code that does a similar job except in a shorter and more understandable way is:
def find_it(seq)
numberWithOddCount = 0
seq.each do |currentElement|
counter = 0
seq.each { |elementToCompare| counter += 1 if currentElement == elementToCompare}
numberWithOddCount = currentElement if counter % 2 != 0
end
numberWithOddCount
end
Just added a few tid-bits that you could also utilize to shorten and simplify code.
Happy Coding!
Note:
You could utilize built in ruby methods in creative ways to make the code do what you want in very few lines (or even one line) such as what #iGian did in the questions comments, but if your still new to ruby then its best to utilize those methods one by one when learning them otherwise you'll be confused. But if your willing to take the time now to learn them, I suggest you take his code and separate each method execution into its own line and output what each method had done to know what's doing what. and practice using each separately.
#aimen_alt is right about your mistake
but let's decompose your problem.
First, you need to calculate the appearances of each number.
Second, you need to find the one with the odd count of the appearances.
Accordingly to the problem, there is only one such number, so you can return it right away.
You can go your way and do it in O(N^2) complexity by scanning your sequence for each item in the sequence (so N items in the sequence multiply by the size of the sequence N = N*N). You can do it linearly* by constructing a Hash and than you'll be able to get the key with odd value:
def find_it(seq)
numbers = {}
seq.each do |item|
numbers[item] = numbers[item].to_i + 1
end
numbers.select{ |k,v| v.odd? }.first.first
end
to be more idiomatic you can use group_by to group the numbers themselves:
seq = [1, 2, 6, 1, 2]
seq.group_by{ |item| item }
#=> {1=>[1, 1], 2=>[2, 2], 6=>[6]}
You can see that each value is an Array, and you just need to get one with the odd amount of items:
seq = [1, 2, 6, 1, 2]
seq.group_by{ |item| item }.select{ |k, v| v.size.odd? }
#=> {6=>[6]}
And the last thing you would like to do is to get the value of the key:
seq.group_by{ |item| item }.select{ |k, v| v.size.odd? }.keys.first
So, the final solution would be
def find_it(seq)
seq.group_by{ |item| item }
.select{ |k, v| v.size.odd? }
.keys
.first
end
as #pascalbetz mentioned:
def find_it(seq)
seq.group_by{ |item| item }
.find{ |k, v| v.size.odd? }
.first
end
def find_it(seq)
seq.group_by{|x| x}.select{|k, v| (v.count % 2.0 !=0)}.first[0]
end
The above code will take a sequence in an array. Here we are grouping by elements:
For example:
[1,1,2,-2,5,2,4,4,-1,-2,5].group_by{|x| x}
# => {1=>[1, 1], 2=>[2, 2], -2=>[-2, -2], 5=>[5, 5], 4=>[4, 4], -1=>[-1]}
after getting the above results, we are finding the whose elements count not odd with the select condition.
ex:
[1,1,2,-2,5,2,4,4,-1,-2,5].group_by{|x| x}.select{|k, v| (v.count % 2.0 !=0)}
we will get the results as {-1=>[-1]}
we are taking the key as result element.
What about this one
def find_it(seq)
seq.reduce(:^)
end
^ -> this symbol is bitwise XOR.
reduce function is taking each value and doing whatever work assigned inside. In this case, it's taking each element and doing an XOR operation. the first element is doing XOR with zero and the next element doing XOR with the previous result and so on.
In this way, we found the odd element.
How XOR operation work
0 ^ 2 = 2
4 ^ 4 = 0
If you want to know more about XOR. kindly refer to this.
Thank you for all the detailed answers, I'm going over everyone's answers now. I'm new to Ruby, and I'm still in the process of learning the methods/rules of using them/Big O notation, so I much appreciated everyone's input. Codewar listed some top ranked solutions. This seems to be the fastest so far:
def find_it(seq)
seq.detect { |n| seq.count(n).odd? }
end

Ruby prime number sum

I am trying to take the sum of the n first prime numbers. I found a way of showing the first 100, but I don't know how to get rid of 1 and how to make a sum with the numbers. I was thinking about storing them into an array, but I can not figure it out.
num = 1
last = 100
while (num <= last)
condition = true
x = 2
while (x <= num / 2)
if (num % x == 0)
condition = false
break
end
x = x + 1
end
primes = [] # Here
if condition
puts num.to_s
primes << num.to_s # Here
end
num = num + 1
end
puts primes.inject(:+) # Here
Based on what I understood from what you guys are saying I added these lines (the ones commented # Here). It still does not print the sum of them. What I meant with getting rid of 1 is that I know that 1 is not considered a prime number, and I do not get how to make it without 1. Thank you very much guys for your time and answers, and please understand that I am just starting to study this.
If you want to add a list of numbers together you can use the following:
list_of_prime_numbers.inject(0) {|total,prime| total + prime}
This will take the list of numbers, and add them one by one to an accumulator (total) that was injected into the loop (.inject(0)), add it to the current number (prime) and then return the total which then becomes the value of total in the next iteration.
I'm not quite sure what you mean by:
I don't know how to get rid of 1
but if you mean to not use the first number (which is 1 in a list of primes starting from 0)
then you could do:
list_of_prime_numbers[1...list_of_prime_numbers.length].
inject(0) {|total,prime| total + prime}
Which would only get all the numbers except the first up to but not including the length of the array
and as for getting the number into the array you could push it into the array like so:
list_of_prime_numbers << prime_number
You can make use of Prime Enumerable in ruby
require 'prime'
((1..100).select { |number| Prime.prime?(number) }).inject(:+)
OR
Prime.each(100).inject(:+)
Hope this helps.

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?

Using for-loop to add numbers together

If I randomly put in two numbers (first number is smaller), how do I use a for-loop to add all the numbers between and itself?
ex:
first number: 3
second number: 5
the computer should give an answer of '12'.
How do I do that using a for-loop?
In Ruby we seldom use a for loop because it leaves litter behind. Instead, you can very simply do what you want using inject:
(3..5).inject(:+) # => 12
This is using some of the deeper Ruby magic (:+), which is a symbol for the + method and is passed into inject. How it works is a different question and is something you'll need to learn later.
Don't insist on doing something in a language using a particular construct you learned in another language. That will often force non-idiomatic code and will keep you from learning how to do it as other programmers in that language would do it. That creates maintenance issues and makes you less desirable in the workplace.
Simple for loop across the range you defined:
puts "Enter first number: "
first = gets.to_i
puts "Enter second number: "
second = gets.to_i
total = 0
for i in (first..second) do
total += i
end
puts total
Note that if you don't enter a valid number, it will converted to 0. Also this assumes the second number is larger than the first.
In Rails, or in plain-vanilla Ruby with ActiveSupport, you can do something even simpler than a for loop, or than what other people wrote.
(first_num..second_num).sum
This is shorthand for sum in Ruby:
sum = 0
(first_num..second_num).each { |num| sum += num }
first, second = [3,5]
for x in (0..0) do
p (first + second)*(second - first + 1) / 2
end
I know you said for loop, but why not use what Ruby gives you?
> a = 3
> b = 5
> a.upto(b).inject(0) {|m,o| m += o}
=> 12
If you insist on a for loop...
> m = 0
=> 0
> for i in 3..5
* m += i
* end
=> 3..5
> m
=> 12
Since Ruby 2.4 you directly call sum on an Enumerable.
For Example [1, 2, 3].sum #=> 6
In Ruby it's very rare to see a for loop. In this instance a more idiomatic method would be upto:
x = 3
y = 5
total = 0
x.upto(y) do |n|
total += n
end
puts total
# => 12
Another method would be to use reduce:
total = x.upto(y).reduce do |sum, n|
sum += n
end
...which can be shortened to this:
total = x.upto(y).reduce(&:+)

The 'upto' method in Ruby

I'm learning Ruby, and there has been a bit of talk about the upto method in the book from which I am learning. I'm confused. What exactly does it do?
Example:
grades = [88,99,73,56,87,64]
sum = 0
0.upto(grades.length - 1) do |loop_index|
sum += grades[loop_index]
end
average = sum/grades.length
puts average
Let's try an explanation:
You define an array
grades = [88,99,73,56,87,64]
and prepare a variable to store the sum:
sum = 0
grades.length is 6 (there are 6 elements in the array), (grades.length - 1) is 5.
with 0.upto(5) you loop from 0 to 5, loop_index will be 0, then 1...
The first element of the array is grades[0] (the index in the array starts with 0).
That's why you have to subtract 1 from the number of elements.
0.upto(grades.length - 1) do |loop_index|
Add the loop_index's value to sum.
sum += grades[loop_index]
end
Now you looped on each element and have the sum of all elements of the array.
You can calculate the average:
average = sum/grades.length
Now you write the result to stdout:
puts average
This was a non-ruby-like syntax. Ruby-like you would do it like this:
grades = [88,99,73,56,87,64]
sum = 0
grades.each do |value|
sum += value
end
average = sum/grades.length
puts average
Addendum based on Marc-Andrés comment:
You may use also inject to avoid to define the initial sum:
grades = [88,99,73,56,87,64]
sum = grades.inject do |sum, value|
sum + value
end
average = sum / grades.length
puts average
Or even shorter:
grades = [88,99,73,56,87,64]
average = grades.inject(:+) / grades.length
puts average
From http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_c_integer.html#upto:
upto int.upto( anInteger ) {| i | block }
Iterates block, passing in integer values from int up to and
including anInteger.
5.upto(10) { |i| print i, " " }
produces:
5 6 7 8 9 10
Upto executes the block given once for each number from the original number "upto" the argument passed. For example:
1.upto(10) {|x| puts x}
will print out the numbers 1 through 10.
It is just another way to do a loop/iterator in Ruby. It says do this action n times based on i being the first number the the number in parens as the limit.
My example would have been this:
1.upto(5) { |i| puts "Countup: #{i}" }
So what you're actually doing here is saying, I want to count up from 1 to the number 5, that's specifically what this part is saying:
1.upto(5)
The latter part of code (a block) is just outputting the iteration of going through the count from 1 up to 5. This is the output you might expect to see:
Countup: 1
Countup: 2
Countup: 3
Countup: 4
Countup: 5
Note: This can be written is another way if you're using multilines:
1.upto(5) do |i|
puts "Countup: #{i}"
end
Hope this helps.
An alternative that looks more like Ruby to me is
require 'descriptive_statistics'
grades=[88,99,73,56,87,64]
sum = grades.sum
average = grades.mean
sd = grades.standard_deviation
Of course it depends what you're doing.

Resources