I'm attempting to combine a few random numbers. The numbers are supposed to represent a dice.
For example, I want to roll the dice 5 times and I get the following results:
4 2 1 4 6.
These are all individual numbers but what I want to do is combine it together as 42146.
This might be a very simple question so I apologize for that but I'm still new to Ruby.
I'm generating numbers between [1,6] through this:
number = 1 + rand(6)
1.upto(5).map { rand(1..6) }.join.to_i
1.upto(5) will give you an Enumerator for 5 elements
map { rand(1..6) } will map a random number between 1 and 6 to each of the above elements
join will concatenate all elements of what you got so far
to_i will transform the above result from string to integer
Although all the answers are correct, there is one more option:
dice = 0
5.times do
dice = dice * 10 + rand(1..6)
end
puts dice
Demo: http://ideone.com/WfagFT
This time you treat everything as integers. Everytime (5 rolls) you take the result variable, multiply it by 10 and then add new random number at the end of it. There's no need to use anything else for that.
Of course if you need it, this code can be also written as one-liner and do exactly the same as above:
p #dice if 5.times { #dice = #dice.to_i * 10 + rand(1..6) }
5.times.inject(0){|n, _| n * 10 + 1 + rand(6)}
p Array.new(5){1 + rand(6)}.join # => "53325"
Related
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(&:+)
Just started learning about loops in ruby and I'm trying to figure out how to add a number to itself.. Like 1+1+1+1+1...
I've tried variations of
3.times() do
self.+(self)
end
But always get undefined method '+'.
I've done this too
number = 1
3.times() do
number = number.+(number)
end
Although it works, it isn't what I'm really trying to do since it's giving me 8, and I just wanted it to be 4 by adding 1+1 over and over. Also I want to be able to use any number not necessarily always 1.
Using times you can do it like:
number = 1
3.times do
number += number
end
puts number
#=> 3
number += number is just a shortcut for number = number + number
Perhaps having another variable to hold onto the sum could fix your issue. Right now, your number starts as 1. Then your loop runs 3 times and looks like the following:
(number = number.+(number))
Loop 1:
number = 1.+(1) ==> 2
number = 2.+(2) ==> 4
number = 4.+(4) ==> 8
Above youre actually multiplying the number by itself X.times
Instead, store the sum of the numbers in a separate variable like this:
sumOfNumbers = 0
numberToAdd = 1
3.times() do
sumOfNumbers = sumOfNumbers.+(numberToAdd)
end
or better yet
sumOfNumbers += numberToAdd
Help me refactor implementing Luhn algorithm, which is described as follows:
The formula verifies a number against its included check digit, which
is usually appended to a partial account number to generate the full
account number. This account number must pass the following test:
From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if the product of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then sum the digits of the products (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9).
Take the sum of all the digits.
If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.
Assume an example of an account number "7992739871" that will have a
check digit added, making it of the form 7992739871x:
Account number 7 9 9 2 7 3 9 8 7 1 x
Double every other 7 18 9 4 7 6 9 16 7 2 -
Sum of digits 7 9 9 4 7 6 9 7 7 2 =67
The check digit (x) is obtained by computing the sum of digits then
computing 9 times that value modulo 10 (in equation form, (67 × 9 mod
10)). In algorithm form:
Compute the sum of the digits (67).
Multiply by 9 (603).
The last digit, 3, is the check digit. Thus, x=3.
Following is my implementation, it works but could be a lot better, I believe.
def credit_check(num)
verify = num.to_s.split('').map(&:to_i)
half1 = verify.reverse.select.each_with_index { |str, i| i.even? }
half1 = half1.inject(0) { |r,i| r + i }
# This implements rule 1
half2 = verify.reverse.select.each_with_index { |str, i| i.odd? }
double = half2.map { |n| n * 2 }
double = double.map { |n| n.to_s.split('') }
double = double.flatten.map(&:to_i)
double = double.inject(0) { |r,i| r + i }
final = double + half1
puts final % 10 == 0 && (num.to_s.length > 12 && num.to_s.length < 17) ? "VALID" : "INVALID"
end
I'm a rank noob at all of this, obviously. But I appreciate any help, including proper style!
Suggestions:
Try to encapsulate your code in a class and provide a intuitive public API. Hide the inner details of the algorithm in private methods.
Break the rules into small methods in the class that has utmost 5 lines, break this rule sparingly. Follow Sandi Metz Rules.
Study the problem and find domain names relevant to the problem; use it to name the small methods.
Focus on readability. Remember this quote: "Programs must be written for people to read, and only incidentally for machines to execute." by Hal Abelson from SICP.
Read Ruby style guide to improve code formatting; and yes get a better editor.
Following these may seem like making the code more verbose. But it will improve readability and help for maintenance. Also, if you tend to follow it even in personal projects, this process will be etched into you and will soon become second nature.
With these in mind, go through the following attempt at the problem:
class CreditCard
VALID_LENGTH_RANGE = 12..17
def initialize(number)
#number = number.to_s
end
def valid?
valid_length? && check_sum_match?
end
private
def valid_length?
VALID_LENGTH_RANGE.include? #number.length
end
def check_sum_match?
check_sum.end_with? check_digit
end
def check_sum
digits = check_less_number
.reverse
.each_char
.each_with_index
.map do |character, index|
digit = character.to_i
index.even? ? double_and_sum(digit) : digit
end
digits.reduce(:+).to_s
end
def check_less_number
#number[0..-2]
end
def check_digit
#number[-1]
end
def double_and_sum(digit)
double = digit * 2
tens = double / 10
units = double % 10
tens + units
end
end
Hence you can use it as follows:
CreditCard.new(222222222224).valid? # => true
CreditCard.new(222222222222).valid? # => false
how about using nested inject method
half2 = verify.reverse.select.each_with_index { |str, i| i.odd? }
double = half2.map { |n| n * 2 }
double = double.inject(0){|x,y| x + y.to_s.split("").inject(0){|sum, n| sum + n.to_i}}
I would implement that algorithm like that:
def credit_card_valid?(num)
digits = String(num).reverse.chars.map(&:to_i)
digits.each_with_index.reduce(0) do |acc, (value, index)|
acc + if index.even?
value
else
double_value = value * 2
if double_value > 9
double_value.to_s.split('').map(&:to_i).reduce(&:+)
else
double_value
end
end
end % 10 == 0
end
Well, that code works for those examples from Wikipedia :)
Here are some advices for you:
get rid of prints/puts to stdin in your function, just return a
value. For this function boolean true/false is good.
ruby community
uses '?' in method names that return false/true
don't forget about
properly formatting your code, but maybe you might've not yet learnt how to do it on Stackoverflow (I haven't yet :)
use 2 spaces for indenting your code
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
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.