I have a set of numbers 123456789
I am writing a loop, so for every 3 numbers/characters it insert a comma, and then starts a new line.
What type of loop would I use for this? And how do I tell ruby for every 3 numbers? "123456.each_char.limit(3)"? I I know limit isnt correct but hopefully im getting the idea accross.
puts 123456789.to_s.gsub(/(.{3})/,"\\1,\n")
result :
123,
456,
789,
alternative loop way :
"123456789".each_char.with_index(1) do |item, index|
if index % 3 == 0
print item + ",\n"
else
print item
end
end
If the set of numbers is a string you can use Enumerable#each_slice to split up the characters into groups of 3 and then join them together before printing to the console:
[21] pry(main)> "123456789".chars.each_slice(3) { |a| p "#{a.join}," }
"123,"
"456,"
"789,"
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'm learning Ruby with 'Learn to Program' by Chris Pine. On chapter 10 I should write a program where the user types as many words as he like and when he's done, he can just press Enter on an empty line and exit.
I came up with this:
puts "Type whatever you want!"
index = 0
word = ''
array = []
while word != nil
word << gets.chomp
array[index] = word
index = index + 1
end
puts ''
puts array.sort
But that doesn't work. What did I miss? Is there another way I could define word without having to repeat it?
The word will not have nil value. It will be an empty string. So you need to check for that:
while word != ""
# or even better
while !word.empty?
Also, you are adding everything to your word. You probably want to assign to it instead:
word = gets.chomp
Per author's comment:
begin
# your code here
end while !word.empty?
# OR more readable
begin
# your code here
end until word.empty?
It seems like there's a simpler solution, if I'm reading the question correctly.
You could do something like this:
user_input = gets.chomp.split(" ").sort
ex)
input: bananas clementine zebra tree house plane mine
output: ["bananas", "clementine", "house", "mine", "plane", "tree", "zebra"]
Here's a simple loop that you could do just for kicks:
arr = []
arr << $_.strip until gets =~ /^\s*$/
puts arr.sort
$_ is a special variable that evaluates to the last input read from STDIN. So basically this reads "Call gets and check if the input is just spaces. If it is then break out of the loop, otherwise append the last input with whitespace removed value onto the array and continue looping."
Or even more fun, a one liner:
puts [].tap {|arr| arr << $_.strip until gets =~ /^\s*$/}.sort
Basically same thing as above except using tap to initialize the variable.
To answer your questions:
Is there another way I could define word without having to repeat it?
Use side effects of assignment. In ruby when you assign a variable the return value of that assignment is the assigned variable, as in:
irb(main):001:0> (variable = 2) == 2
=> true
The idea would be to put the assignment in the your conditional. If I were to write something like this in a comprehensible loop, as opposed to those above, I'd write something like this:
arr = []
while !(word = gets.strip).empty?
arr << word
end
puts arr.sort
Using loop might simplify the code:
a = []
loop do
input = gets.chomp
if input.empty?
break
else
a << input
end
end
a.sort!
puts a
I feel like this should be really easy and I'm just running into a wall.
I need to loop through an array until a condition is met. For example:
count = 0
array = ["","","test","demo"]
I want to loop through this array incrementing count by 1 until the first non-empty value is found. So I want the index value of "test", but when "test" is reached I want to stop the loop.
Also, as a side note, how can I just find the index of the first non-empty value in an array? I want to know both methods as they both have potential application.
You can have both :)
This finds you the index of the first non-empty string:
array = ["","","test","demo"]
array.index {|str| !str.empty?}
#=> 2
You can update count in the {|str| !str.empty?}-block if you like, because Array#index loops from start to end through the array.
FYI: The index method is an alias of find_index
better use :
first_non_empty_index = array.index{ |string| !string.empty? }
do/while:
begin
puts arr[count]
count+=1
end while(arr[count].empty?)
puts count #2
puts arr[count] #test
I have an array containing a large number of contents
Names = ["one", "two", ......."forty"]
Now, I would like to loop through sections of the array. For example, from records 10 to 20, How can I go about this?
I tried this approach -
Names.each_with_index do |val,index|
break if index == 10
puts "#{val}"
end
In this way, I can print the first ten records. What should I do for getting next set of 10 names?
Any help is appreciated.
Cheers!
You can use each_slice to get successive sections of the array. For example:
require 'enumerator'
Names.each_slice(10) do |slice|
slice.each do |x|
puts x
end
puts "----"
end
You can e.g. use the each_slice method:
Names.each_slice(10) {|part|
puts part
}
I am trying to loop through multiple statements, but want to go through each one once, example:
while count < 5 do
count+= (not sure if this how ruby increments counts)
puts "In condition one"
next if count > 1
puts "In condition two"
next if count > 1
#..
end
Update 1:
Thanks for the reply, what I'm trying to do is loop through an array and have each element of the array be applied to 10 different conditions. For example: array[has 100 elements] element 1 gets condition 1, element 2 goes on to condition 2, and so on. Since there are 10 conditions, the 11th element in the array would get condition 1 again, and so on (condition 1 condition 2 condition 3 ...)
Update 2:
Thanks again for taking the time to reply. I apologize that I'm not being very clear. The array contains emails. I have 10 email servers and want to send the 200 emails I have in my array through each server (only 1 email per server). I hope that makes sense
If I'm reading you correctly, you want to send a large number of emails through a small number of servers while balancing the load. Try creating a class to manage the servers (here's the basic idea)
class ServerFarm
def initialize
#servers = []
end
attr_accessor :servers
def add_server(server)
#servers << server
end
def remove_server(x)
if x.is_a?(Numeric) then
#servers.delete_at(x)
elsif x.is_a?(Server)
#servers.delete(x)
end
end
def server_available?
#servers.each {|s| return true if s.available? }
false
end
def dispatch_message(email)
#servers.each_with_index {|s, i|
next unless s.available?
s.dispatch(email)
return i
}
nil
end
end
Now, all you will have to do is call ServerFarm.dispatch_message for an email and it will be sent using one of the available servers. This class assumes that you have a class named Server that holds the info for your individual servers, etc etc.
array = (1..100).to_a
conditions = (1..10).to_a
array.each_with_index do |elem, i|
puts "element %d, using condition %d" % [elem, conditions[i % conditions.length]]
end
produces
element 1, using condition 1
element 2, using condition 2
element 3, using condition 3
element 4, using condition 4
element 5, using condition 5
element 6, using condition 6
element 7, using condition 7
element 8, using condition 8
element 9, using condition 9
element 10, using condition 10
element 11, using condition 1
element 12, using condition 2
etc.
Does this help? I can't tell what you are trying to do.
5.times do |count|
puts 'In condition ' + %w(one two three four five)[count]
end
The 5.times do |count| will excecute the block five times with count starting at zero and incrementing each time. %w(one two three four five) is the same as ["one", "two", "three", "four", "five"].
If you want to do five different things consecutively, you do not need a loop. Just put the statements in a row:
# do thing 1
# do thing 2
# do thing 3
# ...
Edit:
"I have an array that I want to loop through, but each element in the array needs to go through a different condition each time and then restart at the first condition."
To loop through an array endlessly, testing each element against conditions:
arr = ['sdfhaq', 'aieei', 'xzhzdwz']
loop do
arr.each do |x|
case x
when /..h/
puts 'There was a \'h\' at the third character.'
when /.{6}/
puts 'There were at least six characters.'
else
puts 'None of the above.'
end
end
end
Edit 2:
"Thanks for the reply, what I'm trying to do is loop through an array and have each element of the array be applied to 10 different conditions, example: array[has 100 elements] element 1 gets condition 1 element 2 goes on to condition 2 and so on, since there are 10 conditions the 11th element in the array would get condition 1 again and so on. condition 1 condition 2 condition"
You will need to use the % method on numbers.
arr = Array.new(130) # an array of 130 nil elements.
num_conditions = 10
arr.each_with_index do |x, i|
condition = (i + 1) % num_conditions
puts "Condition number = #{condition}"
end
More information: http://ruby-doc.org/core/classes/Fixnum.html#M001059
Edit three:
def send_an_email(email, server)
puts "Sending an email with the text #{email.inspect} to #{server}."
end
email_servers = ['1.1.1.1', '2.2.2.2']
emails = ['How are you doing?', 'When are you coming over?', 'Check out this link!']
emails.each_with_index do |email, i|
send_an_email email, email_servers[i % email_servers.length]
end
You can modify email_servers and emails and have it still work, even if the lengths are changed.
array.each_slice(10) do |emails|
servers.zip(emails) { |server,email| server<<email }
end
(Ruby 1.9.2)