Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Which is better?
string.each_char do |letter|
unless letter == " "
if letters.has_key?(letter)
letters[letter] = letters[letter].next
else
letters[letter] = 1
end
end
end
or
string.each_char do |letter|
if letter == " "
elsif letters.has_key?(letter)
letters[letter] = letters[letter].next
else
letters[letter] = 1
end
end
It seems awkward to leave an if statement without the body, but it also seems preferable to going a step deeper with unless.
There's a better way to write this code. I didn't know about default Hash values, and that would clean this code up a lot, but I still wanted to know which is preferable: an if statement without body, or unless, or something else.
This is probably the nicest:
letters = Hash.new(0)
string = "aaabbc"
string.each_char do |letter|
if letter != " "
letters[letter] += 1
end
end
# => {"a"=>3, "b"=>2, "c"=>1}
For deciding between your two examples, I would avoid adding extra-depth (more indentation). The second one is also easier to read because it's simple to follow a string of if/else statements. It's almost always preferable to have more readable code than fancy code.
You can set the default value for a hash when constructing:
letters = Hash.new(0)
...
letters[letter] = letters[letter].next
An interesting approach using this is to use some of the map / reduce methods offered by Ruby:
letters = string.chars
.reject{ |letter| letter == " " }
.each_with_object(Hash.new(0)) { |letter, memo|
memo[letter] = memo[letter].next
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm very puzzled with this simple method I have where I'm just trying to puts a character of an array if, when compared with the character of another array, it is different.
This works with the == operator but not with the !=
Maybe it has to do with the each loops but I can't see what the error is. Any ideas?
Thanks
def remove_vowels(s)
nw_s = s.chars
vowels = "aeiou".chars
result = []
nw_s.each do |char|
vowels.each do |vowel|
if char != vowel
print char
end
end
end
end
remove_vowels("apple")
Nested each is no ruby way of doing this kind of task. You can write this
def remove_vowels(s)
nw_s = s.chars
vowels = "aeiou".chars
result = nw_s.map {|k| k unless vowels.include?(k) }.compact
end
remove_vowels("apple")
One line of code instead seven
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm new to ruby, and I'm trying to make a simple calculator in which a user types in a simple problem (such as addition or subtraction) and the answer is returned. The problem is when the user types in a question, the question itself is being returned instead of the answer to that question.
puts "How many Questions?"
questions = gets.chomp.to_i
questions.times do |problem|
puts "question: "
problem = gets.chomp
puts "answer: #{problem}"
end
Inside your loop, instead of:
problem = gets.chomp
puts "answer: #{problem}"
Try this:
problem = gets.chomp
solved_problem = eval(problem)
puts "answer : #{solved_problem}"
eval will take care of interpreting your string as a Ruby instruction. But it's very messy, because anyone could write any Ruby program in your input and eval will make it run, so it's not safe at all.
If you only want to take care of simple operations, you can use a regex first to check if the input string looks like what you want:
problem_is_ok = (problem =~ /^\d+ *[+-] *\d+$/)
This will be true if the string starts with a number, followed by 0 to many spaces, followed by either a + or - sign, followed by 0 or more spaces, followed by another number and nothing else. Then you raise an error if this is not true.
Your loop now look like this:
questions.times do |problem|
puts "question: "
problem = gets.chomp
problem_is_ok = (problem =~ /^\d+ *[+-] *\d+$/)
if problem_is_ok
puts "answer: #{eval(problem)}"
else
#I raise an error, but you might aswell just print it instead for your simple program
raise ArgumentError("Can't compute this")
end
end
Add and subtract can be simple ruby definitions
We pass in 5 and 1
The lower portion of the code is the clear user interface implementation
when we loop we do it 3 times
It outputs 3 options for the user to select from
We read in with chomp, standard in, the keyboard, chooses 1, 2, or 3
If elsif statements conditionally select for each case
Using string interpolation we render the variables a and b into a new string,
and run their respective methods (add or subtract)
Converting that methods integer output to a string, and concatenate it.
Outputting that to the users screen
The 3rd option does no calculation,
instead it prints to users screen a simple string
our else condition catches the case when people don't enter one of the choices of 1, 2 or 3
It tells you to correct your choice to the options provided
Hope this helps
#!/usr/bin/env ruby
questions = 3
a, b = 5, 1
def add(a,b)
a + b
end
def subtract(a,b)
a - b
end
questions.times do |questions|
puts "Please choose:
1. add
2. subtract
3. exit"
questions = gets.chomp
if questions == '1'
puts "#{a} + #{b} = " + add(a,b).to_s
elsif questions == '2'
puts "#{a} - #{b} = " + subtract(a,b).to_s
elsif questions == '3'
puts 'exiting, goodbye.'
exit
else
p 'please choose again'
end
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
The first code works, but I don't understand why the second one doesn't. Any insight would be appreciated. I know in this example I really don't need an array, I just wanted to get it to work for the sake of learning.
def stamps(input)
if input % 5 == 0
puts 'Zero!'
else
puts 'NO!'
end
end
print stamps(8)
But this doesn't work:
array_of_numbers = [8]
def stamps(input_array)
if input_array % 5 == 0
puts 'Zero!'
else
puts 'NO!'
end
end
print stamps(array_of_numbers)
Because input_array is an array and 8 is a number. Use first to retrieve the first element of the array.
array_of_numbers = [8]
def stamps(input_array)
if input_array.first % 5 == 0
puts 'Zero!'
else
puts 'NO!'
end
end
print stamps(array_of_numbers)
The following function works in case the input is number or array:
def stamps(input)
input = [input] unless input.is_a?(Array)
if input.first % 5 == 0
puts 'Zero!'
else
puts 'NO!'
end
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I was hoping something like this would work:
while i < 3 do
puts i
#b[i] = Benchmark.new
i += 1
#a += 1
end
puts "Here is a #{#a}"
puts #b0.inspect
puts #b1.inspect
puts #b2.inspect
Sadly, it doesn't work at all. []= is regarded as an unrecognised method!
You can also use instance_variable_set
3.times{|i| instance_variable_set "#x#{i}", i }
#x1 # => 1
#x2 # => 2
Though for this particular task you should use arrays, it's a rookie mistake to use lots of variables instead of lists.
benchmarks = []
n.times { benchmarks << Benchmark.new } # or benchmarks = (0..n).map { Benchmark.new }
benchmarks.each do |bm|
# do stuff
end
This is clearly a job for an array, not for many instance variables.
benchmarks = number.times.map { Benchmark.new }
puts "Here is a #{number}"
benchmarks.each { |b| puts b.inspect }
Answered my own question! The eval method is the answer:
puts "Welcome to Benchmark 1.0! How many benchmarks do you wish to perform? (We recommend three)"
number = gets.chomp.to_i
#a = 0
i = 0
while i < number do
puts i
eval("#b#{i} = Benchmark.new")
i += 1
#a += 1
end
puts "Here is a #{#a}"
puts #b0.inspect
puts #b1.inspect
puts #b2.inspect
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
The code below gets some text, find commas, and returns an array of a split up version without the commas.
class A
def separate_comma_values(text)
txt_len = text.length
if txt_len == 0
return [""]
end
final = []
sub_arry = ""
for i in (0...txt_len)
ch = text[i]
if ch == ","
final << sub_arry
final << ""
sub = ""
else
sub_arry += ch
end
end
return final
end
end
This is a sample input and output:
s = A.new
print s.separate_comma_values("dh,,,dhhd,jhb")
# => ["dh", "", "dh", "", "dh", "", "dhdhhd", ""]
Although it does what I want it to do, I feel that there is something just not right about it. It's just dirty.
I am aware that I can use a built in method provided by ruby to achieve the split.
Edit: I guess this was edit out of my original post. The motivation behind this was to apply the knowledge I found after reading a ruby book.
There's a method in Ruby that does what you want.
http://ruby-doc.org/core-2.0/String.html#method-i-split
2.0.0p0 :001 > "dh,,,dhhd,jhb".split(',')
=> ["dh", "", "", "dhhd", "jhb"]
So, your code might end up being as simple as
def separate_comma_values(text)
text.split(',')
end
Update: Sorry, I missed the part where you mention you already know about split. Oops.
The only proper way to refactor your code is, obviously, to use String#split.
Although, just for fun:
def separate_comma_values(text)
text.each_char.reduce(['']) do |splitted, char|
if char == ','
splitted << ''
else
splitted.last << char
end
next splitted
end
end
Just as a small trick for looking nicer (in my opinion), you should be able to skip the word 'return' at the end of the method, and your 'seperate_comma_values(text)' could be just 'seperate_comma_values text' without the parens (in your text editor, syntax color highlighting makes this not a problem of clarity at all)
This is a little cleaner, although as #depa points out, if you're trying to split based on commas, there's an easier way, and your (and thus this) code doesn't work right.
class A
def separate_comma_values(text)
return [""] if text.empty?
final = []
sub_arry = ""
text.each_char do |ch|
if ch == ","
final << sub_arry
final << ""
else
sub_arry += ch
end
end
return final
end
end
s = A.new
print s.separate_comma_values("dh,,,dhhd,jhb")
puts
This outputs
["dh", "", "dh", "", "dh", "", "dhdhhd", ""]
just as your does.
Here's how I would implement your algorithm:
class A
def separate_comma_values(text)
return [""] if text.empty?
array = []
value = ""
text.each_char do |c|
if c == ","
array << value
value = ""
else
value += c
end
end
array << value if !value.empty?
array
end
end
s = A.new
print s.separate_comma_values("dh,,,dhhd,jhb")
puts
This outputs
["dh", "", "", "dhhd", "jhb"]