I got the task to create a lottery program which outputs 6 random numbers from 1 to 49 without duplicates. I'm not allowed to use the shuffle-Method of Arrays and as a tip I recieved that I should create an array with 49 entries and "shuffle" the numbers. I thought about this tip but it's not really helping.
This is what I got till now, I hope someone understands my code. I'm still stuck in a more Java way of writing than in ruby.
# Generating the Array
l_num = Array.new(6)
i = 0
while (i == 0)
l_num << [rand(1...49), rand(1...49), rand(1...49), rand(1...49), rand(1...49), rand(1...49)]
if (l_num.uniq.length == l_num.length)
i += 1
end
end
#Output
puts 'Todays lottery numbers are'
l_num.each { |a| print a, " " }
I picked up the uniq-Methode, because I read that it could elimante doubles that way, but I don't think it works in this case. In previous versions of my code I got a Error because I was trying to override the allready created array, I understand why Ruby is giving me an error but I have no clue how to do it in another way.
I hope someone is able to provide me some code-pieces, methods, solutions or tips for this task, thanks in advance.
This is the strategy I would take:
lottery_numbers = []
begin
# add 1 because otherwise it gives you numbers from 0-48
number = rand(49)+1
lottery_numbers.push(number) unless lottery_numbers.include?(number)
end while lottery_numbers.size < 6
puts "lottery numbers:"
puts lottery_numbers.join(" ")
Rubyists tend to initialize arrays with [] as opposed to the verbose Array.new
Charles, I think the easiest would be the following:
Array.new(49) { |x| x + 1 }.sample(6)
However this is what I believe you was prohibited to do? If yes, try a more "manual" solution:
Array.new(49) { |x| x + 1 }.sort { rand() - 0.5 }.take(6)
Otherwise, try implementing one completely "manual" solution. For example:
require 'set'
result = Set.new
loop do
result << 1 + rand(49)
break if result.size == 6
end
puts result.to_a.inspect
Here's one way to do it you can't use sample:
a = *1..49
#=> [1, 2, 3,..., 49]
6.times.map { a.delete_at(rand(a.size))+1 }
# => [44, 41, 15, 19, 46, 17]
min_lottery_number = 1
max_lottery_number = 49
total_size = 6
(min_lottery_number..max_lottery_number).to_a.sample(total_size)
Related
Currently, I'm having print like this
print ((stamp_amount[0], 'first mark') unless stamp_amount[0].zero?), (', ' if !stamp_amount[0].zero? && !stamp_amount[1].zero?),
((stamp_amount[1], 'second mark') unless stamp_amount[1].zero?)
stamp_amount is an array with 2 integer values
Let's say in the current situation stamp_amount[0] = 10 and stamp_amount[1] = 3
Output preview:
10 first mark, 3 second mark
So if stamp_amount[0] = 0 the 10 first mark, part won't be show. Same if stamp_amount[1] = 0 the , 3 second mark part won't be shown
For me, it seems a little bit incorrect in terms of theory. Could you please suggest me the more correct or less painful print of this? :)
Cheers!
Your code is trying to join a sequence of up to two elements with a separator. The joining is a solved problem, see Array#join.
The problem can be then reduced to "how can I produce the correct sequence, given my stamp_amount input". Now this can be done in a thousand ways. Here's one:
def my_print(stamp_amount)
ary = [
!stamp_amount[0].zero? && stamp_amount[0],
!stamp_amount[1].zero? && stamp_amount[1],
].select{|elem| elem }
ary.join(', ')
end
my_print([10, 3]) # => "10, 3"
my_print([0, 3]) # => "3"
my_print([10, 0]) # => "10"
my_print([0, 0]) # => ""
Here's another
ary = []
ary << stamp_amount[0] unless stamp_amount[0].zero?
ary << stamp_amount[1] unless stamp_amount[1].zero?
ary.join(', ')
Here's yet another. This version can handle stamp_amount of any length.
ary = stamp_amount.reject(&:zero?)
ary.join(', ')
I'd go with the third, but the second one may be the easiest to understand for a beginner.
Use the select, as an alternative to reject (shown in part 3 of the answer by Sergio Tulentsev). It is just asa readable, and depending on the context and on the future changes to the code, you may prefer one versus the other.
puts stamp_amount.select{ |a| !a.zero? }.join(", ")
A few examples of inputs and outputs are:
stamp_amount output
--------------------------------------------------------------------------
10, 3 10, 3
10, 0 10
0, 3 3
0, 0 (prints an empty line, because the selected array is empty)
You're calculating zero? on index points more often than is needed, but the first thing I would look at refactoring here is the readability of the code. It might be nicer to calculate the message to print outside of the print method and explain what is happening with variable names.
# rubocop is going to complain about variable assignment like this
first_amount, second_amount = *stamp_amount
We can actually use the reason rubocop prefers the .zero? over == 0 or .empty? method to guide our development. zero? is in essence just empty? but it communicates the meaning of what you are attempting to do in a better manner. I would use this reasoning when assigning strings to variables that explain what they are doing.
some_name_that_explains_what_this_is_0 = "#{first_amount} piecu centu marka"
some_name_that_explains_what_this_is_1 = "#{second_amount} tris centu marka"
Your current code is confusing as you have the possibility of printing a string like "10 tris centu marka" which does not make lexical sense and probably not what you are after considering tis evaluates to 'second mark', which would pose an issue if the first value is zero. We also could reject zero integers before we start converting them to strings.
array = [1, 0].reject(&:zero?)
Now we can take the array and do something like:
string = []
array.each_with_index { |e, i| string << "#{e} #{Ordinalize.new(i).ordinalize} mark" }
message = string.join(', ')
print(message)
# ord class
class Ordinalize
def initialize(value)
#value = value
end
def ordinalize
mapping[#value]
end
def mapping
# acounting for zero index
['first', 'second']
end
end
where we are calculating the ordinalization and letting our new class handle the sentence structure for us.
Outputs:
[1, 0] => "1 first mark"
[0, 1] => "1 first mark"
[1, 2] => "1 first mark, 2 second mark"
I am trying to return the index's to all occurrences of a specific character in a string using Ruby. A example string is "a#asg#sdfg#d##" and the expected return is [1,5,10,12,13] when searching for # characters. The following code does the job but there must be a simpler way of doing this?
def occurances (line)
index = 0
all_index = []
line.each_byte do |x|
if x == '#'[0] then
all_index << index
end
index += 1
end
all_index
end
s = "a#asg#sdfg#d##"
a = (0 ... s.length).find_all { |i| s[i,1] == '#' }
require 'enumerator' # Needed in 1.8.6 only
"1#3#a#".enum_for(:scan,/#/).map { Regexp.last_match.begin(0) }
#=> [1, 3, 5]
ETA: This works by creating an Enumerator that uses scan(/#/) as its each method.
scan yields each occurence of the specified pattern (in this case /#/) and inside the block you can call Regexp.last_match to access the MatchData object for the match.
MatchData#begin(0) returns the index where the match begins and since we used map on the enumerator, we get an array of those indices back.
Here's a less-fancy way:
i = -1
all = []
while i = x.index('#',i+1)
all << i
end
all
In a quick speed test this was about 3.3x faster than FM's find_all method, and about 2.5x faster than sepp2k's enum_for method.
Here's a long method chain:
"a#asg#sdfg#d##".
each_char.
each_with_index.
inject([]) do |indices, (char, idx)|
indices << idx if char == "#"
indices
end
# => [1, 5, 10, 12, 13]
requires 1.8.7+
Another solution derived from FMc's answer:
s = "a#asg#sdfg#d##"
q = []
s.length.times {|i| q << i if s[i,1] == '#'}
I love that Ruby never has only one way of doing something!
Here's a solution for massive strings. I'm doing text finds on 4.5MB text strings and the other solutions grind to a halt. This takes advantage of the fact that ruby .split is very efficient compared to string comparisions.
def indices_of_matches(str, target)
cuts = (str + (target.hash.to_s.gsub(target,''))).split(target)[0..-2]
indicies = []
loc = 0
cuts.each do |cut|
loc = loc + cut.size
indicies << loc
loc = loc + target.size
end
return indicies
end
It's basically using the horsepower behind the .split method, then using the separate parts and the length of the searched string to work out locations. I've gone from 30 seconds using various methods to instantaneous on extremely large strings.
I'm sure there's a better way to do it, but:
(str + (target.hash.to_s.gsub(target,'')))
adds something to the end of the string in case the target is at the end (and the way split works), but have to also make sure that the "random" addition doesn't contain the target itself.
indices_of_matches("a#asg#sdfg#d##","#")
=> [1, 5, 10, 12, 13]
I am starting to learn ruby and am trying to figure out a way to if i have an array of 16 numbers, to print those numbers 4 at a time using only the each method. I can easily do this with a loop but i am lacking full understanding of the each method in Ruby so this gives me some trouble.
I have the following:
x=[*1..16]
index=0
x.each do |element|
puts element[index]
index=index+3
end
Now obviously this is completely wrong and i know that but i wanted to put something on here. A little advice would be great.
Thank you
A possible solution:
a = (1..16)
a.each_slice(4) { |s| p s[3] }
EDIT: If you want print 4 elements on one line, then skip to the next line and print the next 4 elements, etc
a = (1..16)
a.each_slice(4) { |s| puts s.join(' ') }
Or using each only
a = (1..16)
a.each { |i| print i.to_s + ' '; print "\n" if i % 4 == 0 }
Try each_slice http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-each_slice.
Using that would look something like
(1..16).each_slice(4) do |x|
puts x.inspect
end
I'm learning Ruby since yesterday evening.
Here's a method I made that's supposed to print out multiples of any numbers up to any quantity.
def DisplayMultiples(multiplesOf, count)
i = multiplesOf
while i <= count
if i % multiplesOf == 0
puts i
end
i += 1
end
end
Any suggestions on how to improve the code to something more fitting to the Ruby style? I'm coming from a C# background so I'd like to switch things up a bit.
Edit:
Where can I find documentation for methods/classes? For example, the first answer I received use the .times method (is it a method?). I can't find the documentation for that because I don't know what type it is, since Ruby doesn't have types.
Any suggestions?
I'd do:
def display_multiples(multiplesOf, count)
count.times {|x| puts x * multiplesOf }
end
def display_multiples(number, limit)
0.step(limit, number){|n| puts n}
end
def display_multiples(multiplesOf, count)
(count/multiplesOf).times {|x| puts (x+1) * multiplesOf }
end
As for documentation, see ruby-doc.org and gotapi.com.
def display_multiples(of,nb)
p (of..of*nb).step(of).to_a
end
display_multiples(3,5) #display [3, 6, 9, 12, 15]
code:
c = 0
items.each { |i|
puts i.to_s
# if c > 9 escape the each iteration early - and do not repeat
c++
}
I want to grab the first 10 items then leave the "each" loop.
What do I replace the commented line with? is there a better approach? something more Ruby idiomatic?
While the break solution works, I think a more functional approach really suits this problem. You want to take the first 10 elements and print them so try
items.take(10).each { |i| puts i.to_s }
There is no ++ operator in Ruby. It's also convention to use do and end for multi-line blocks. Modifying your solution yields:
c = 0
items.each do |i|
puts i.to_s
break if c > 9
c += 1
end
Or also:
items.each_with_index do |i, c|
puts i.to_s
break if c > 9
end
See each_with_index and also Programming Ruby Break, Redo, and Next.
Update: Chuck's answer with ranges is more Ruby-like, and nimrodm's answer using take is even better.
break works for escaping early from a loop, but it's more idiomatic just to do items[0..9].each {|i| puts i}. (And if all you're doing is literally printing the items with no changes at all, you can just do puts items[0..9].)
Another option would be
items.first(10).each do |i|
puts i.to_s
end
That reads a little more easily to me than breaking on an iterator, and first will return only as many items as available if there aren't enough.
Another variant:
puts items.first(10)
Note that this works fine with arrays of less than 10 items:
>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5
(One other note, a lot of people are offering some form of puts i.to_s, but in such a case, isn't .to_s redundant? puts will automatically call .to_s on a non-string to print it out, I thought. You would only need .to_s if you wanted to say puts 'A' + i.to_s or the like.)
Does this look like what you want?
10.times { |i|
puts items[i].to_s
}
items.each_with_index { |i, c| puts i and break if c <= 9 }
It was asked:
I want to grab the first 10 items then leave the "each" loop.
Use throw and catch to accomplish this, with few changes to the example:
catch(:done) do
c = 0
collected = []
items.each do |item|
collected << item
throw(:done, collected) if c == 9 # started at 0
c += 1
end
collected # if the list is less than 10 long, return what was collected
end
Simply throw the label :done with collected and the catch which is waiting for :done will return collected.
And to "ruby" this up a bit:
catch(:done) do
items.inject([]) do |collected, item|
throw(:done, collected) if collected.size == 10
collected << item # collected gets returned here and populates the first argument of this block
end
end
I do not know why some people refuse to use inject and use reduce instead (they are equivalent) when clearly the empty array given to inject([]) is being injected with items! Anyhow, the inject will return collected if there are less than 10 items.
Most answers are trying to answer what might be the intent of the question instead of what was asked and items.take(10) does make perfect sense in that case. But I can imagine wanting to grab the first items that fit within my $100 budget. Then you can simply:
catch(:done) do
items.inject({items: [], budget: 100}) do |ledger, item|
remainder = ledger[:budget] - item.price
if remainder < 0
throw(:done, ledger)
else
ledger.tap do |this|
this[:items] << item
this[:budget] = remainder
end # tap just returns what is being tapped into, in this case, ledger
end
end
end