I have to create the following pattern:
*
**
***
****
*****
Using a ARGV and this is what I have so far:
height = ARGV[0]
output = ""
height.to_i.times do |i|
output << "*" * i
output << "\n"
end
puts output
But every time I run ruby pyramid.rb 5 on my mac terminal, I get the following output:
$ ruby pyramid.rb 5
*
**
***
****
Why is it giving me 4 when it needs to have 5 of them?
Integer#times yields values from 0 to n-1, so you're getting lines of 0 up to 4 stars.
You mentioned this was an exercise, so I'll leave the fix up to you.
In general, to troubleshoot these kinds of problems, it's best to use a debugger or add diagnostic printing (e.g. puts statements) to trace the values of variables and ensure they're what you expected.
For example, in this case, you could add puts i inside your loop to see what the value of i is at every iteration. You would see something like 0 1 2 3 4 printed, which isn't what you expected. From there, you can look at your code, documentation, or add more diagnostic output to determine why you get those values.
I know this thread is old but I felt it's better late than never. Chris hinted at the solution. If i is starting from zero, you just have to make it so that i starts from 1 by simple adding i += 1. see example below:
height = ARGV[0]
output = ""
height.to_i.times do |i|
i += 1
output << "*" * i
output << "\n"
end
puts output
Analysis
The problem in your code is the use of Integer#times. Per the documentation, the #times method:
[i]terates the given block int times, passing in values from zero to int - 1.
So, here is your given code, with comments:
height.to_i.times do |i| # when `height = 5`, equivalent to `(0..4).each`
output << "*" * i # will be "" on the first pass when i == 0
output << "\n"
end
Solution
In this case, you should use the Integer#upto method instead of Integer#times, with 1 as your starting value. Consider the following example, rewritten as a one-liner you can run from the command prompt:
$ ruby -e '1.upto(Integer(ARGV[0])) { |i| puts "*" * i }' 5
*
**
***
****
*****
In addition to giving the expected results on standard output, it also does away with string mutation, declaring an output variable, and other non-essentials. The use of Kernel#Integer will also raise an exception if ARGV[0] can't be cast as an integer, rather introducing subtle bugs such as when ARGV[0] == "".
Related
EDIT: SOLVED BY STEFAN
BUT: Now, the only questions left are: Why has the shorter solution such a poor performance (results: 100%, performance: 32%, result: 66%) , while the longer version performs a bit better but seems to produce worse results (60%, 50%, 55%)?
Start of original question:
I'm currently trying the Codility demo test and the problem to solve is to find the lowest integer above 0 that's not included in a given array.
This is my code in two different versions with the same result. The output is right but the compiler throws the abovementioned error, resulting in the test failing. This seems to be a common error on Codility, when looking up this error here on SO.
# you can write to stdout for debugging purposes, e.g.
# puts "this is a debug message"
def solution(a)
# write your code in Ruby 2.2
num = 1
a=a.sort
a.uniq!
a.each do |x|
if x == num then
num += 1
next
else
break
end
end
puts num
end
or
def solution(a)
# write your code in Ruby 2.2
num = 1
while a.include?(num) do
num += 1
end
puts num
end
results in:
Compilation successful.
Example test: [1, 3, 6, 4, 1, 2]
Output (stderr):
Invalid result type, Integer expected, NilClass found
Output:
5
RUNTIME ERROR (tested program terminated with exit code 1)
Example test: [1, 2, 3]
Output (stderr):
Invalid result type, Integer expected, NilClass found
Output:
4
RUNTIME ERROR (tested program terminated with exit code 1)
Example test: [-1, -3]
Output (stderr):
Invalid result type, Integer expected, NilClass found
Output:
1
RUNTIME ERROR (tested program terminated with exit code 1)
Producing output might cause your solution to fail performance tests.
You should remove code that produces output before you submit your solution.
Detected some errors.
I really don't understand what's wrong. The array only contains integers, num is an integer, everything is an integer but the compiler says it's NIL. What can I do?
EDIT: The same code runs without errors in the SoloLearn app and on my local machine.
The output is right but the compiler throws the abovementioned error, resulting in the test failing
Although puts generates output it has a return value of nil:
puts 123
# 123 # <- output
#=> nil # <- return value
I assume that your method is supposed to return the value instead just printing it to standard out.
You can fix this by removing puts in your method's last line:
def solution(a)
num = 1
while a.include?(num)
num += 1
end
num # <- without "puts"
end
To generate debug output you could add puts num on a separate line before the return value, e.g.:
def solution(a)
# ...
puts num # <- prints num
num # <- returns num
end
or you could use p which outputs the object's inspect value and returns the object:
def solution(a)
# ...
p num # <- prints num.inspect and returns num
end
Regarding the performance: try to understand what the code has to do in order to get the result. The "short" solution increments num and checks whether it is included in the array. But an inclusion check has to traverse the array (at least up to the matching element). So for each increment of num, you are traversing the array from the beginning.
You can speed this up significantly by utilizing Set for the lookup:
require 'set'
def solution(a)
set = Set.new(a)
num = 1
num += 1 while set.include?(num)
num
end
def solution(a)
range = (1..a.max).to_a
(range - a).first
end
If you are printing within the code just remove that lines
for Ex in Javascript remove used console.log
Can anyone tell me why this program is not producing an output? The output it should be producing is: Line read: 0
Line read: 1 Line read: 2 Line read: 3 and so on.
So far, I am not getting an output even though I have fixed a number of bugs. Any help or suggestions would be much appreciated.
# takes a number and writes that number to a file then on each line
# increments from zero to the number passed
def write(aFile, number)
# You might need to fix this next line:
aFile.puts(number)
index = 0
while (index < number)
aFile.puts(index.to_s)
index += 1
end
end
# Read the data from the file and print out each line
def read(aFile)
# Defensive programming:
count = aFile.gets
if (is_numeric?(count))
count = count.to_i
index = 0
while (index < count)
line = aFile.gets
puts "line read: " + line
index+=1
end
end
end
# Write data to a file then read it in and print it out
def main
aFile = File.new("mydata.txt", "w") # open for writing
write(aFile, 10)
aFile.close
aFile = File.new("mydata.txt", "r")
read(aFile)
aFile.close
end
# returns true if a string contains only digits
def is_numeric?(obj)
if /[^0-9]/.match(obj) == nil
true
end
false
end
main
Your code isn't written in the Ruby way.
This is how I'd write it if I wanted to closely mimic your code's logic:
# takes a number and writes that number to a file then on each line
# increments from zero to the number passed
def write_data(fname, counter)
File.open(fname, 'w') do |fo|
fo.puts(counter)
counter.times do |n|
fo.puts n
end
end
end
# returns true if a string contains only digits
def is_numeric?(obj)
obj[/^\d+$/]
end
# Read the data from the file and print out each line
def read_data(fname)
File.open(fname) do |fi|
counter = fi.gets.chomp
if is_numeric?(counter)
counter.to_i.times do |n|
line_in = fi.gets
puts 'Line read: %s' % line_in
end
end
end
end
# Write data to a file then read it in and print it out
DATA_FILE = 'mydata.txt'
write_data(DATA_FILE, 10)
read_data(DATA_FILE)
Which outputs:
Line read: 0
Line read: 1
Line read: 2
Line read: 3
Line read: 4
Line read: 5
Line read: 6
Line read: 7
Line read: 8
Line read: 9
Notice these things:
Method (or variable) names are not in camelCase in Ruby, they're snake_case. ItsAReadabiltyThing.
Ruby encourages us to use a block when opening files for reading or writing, to automatically close the file when we're finished with it. Leaving danging file handles opened then not closed, in a loop, in a long-running program, is a great way for your program to crash in a way that's hard to figure out. SO has many questions that resulted from doing that. This is from the IO#open documentation:
With no associated block, ::open is a synonym for ::new. If the optional code block is given, it will be passed io as an argument, and the IO object will automatically be closed when the block terminates. In this instance, ::open returns the value of the block.
Usually you'll see code use File.open instead of IO.open, mostly out of habit in Ruby coders. File inherits from IO and adds some additional file-oriented methods to the class, so it's a little more full-featured.
Ruby has many methods that help us avoid using while loops. Getting the counters wrong or missing a condition that should terminate the loop, is all too common in programming, so Ruby makes it easy to loop "n times" or to iterate over all the elements in an array. The times method accomplishes that nicely.
String's [] method is really powerful and makes it easy to look at the contents of a string and apply a pattern or a slice. Using /^\d+$/ checks the entire string to make sure all characters are digits, so some_string[/^\d+$/] is a shorter version than what you're doing and accomplishes the same thing, returns a "truthy" value.
We don't use a main method. That's old-school Pascal, C or Java and is artificially structured. Ruby's a little more friendly than that.
Instead of using
3.times do |n|
puts n
end
# >> 0
# >> 1
# >> 2
I'd probably use
puts (0..(3 - 1)).to_a * "\n"
# >> 0
# >> 1
# >> 2
just because I tend to think in Perl terms. It's another old habit.
I found 2 errors. Fixing those errors gives you desired output.
Error #1.
Your method is_numeric? always returns false. Even if your condition is true. The last line of the method is false and therefore the whole method ALWAYS returns false.
You can fix it in 2 steps.
Step #1:
if /[^0-9]/.match(obj) == nil
true
else
false
end
It's not a good practice to return booleans within conditional. You can simplify it this way:
def is_numeric?(obj)
/[^0-9]/.match(obj) == nil
end
or even better
def is_numeric?(obj)
/[^0-9]/.match(obj).nil?
end
Error #2 is inside your read method. If you try to output the value of count after you read it from the file it gives you "10\n". That \n at the end messes you up.
To get rid of \n when you read from the file you could possibly use chomp. So then your reading line would be:
count = aFile.gets.chomp
and the rest works like magic
I'm practicing the While Loop in Ruby and got a basic example as below
i = 3
while i > 0 do
print i
i -= 1
end
My question is why I can't interchange do..end with {} as if I rewrite the above code as below it doesn't work anymore
i = 3
while i > 0 {
print i
i -= 1
}
However, it seems to work without the first "do"
i = 3
while i > 0
print i
i -= 1
end
Could anyone explain the rule or redirect me to the right resource? Thx!
As you said do is optional for while loop. While keyword is enough to define a block which is finished with end like any other block in ruby. In addition, end is mandatory for while block.
If you want to use while on just one line you can do such as below:
i = 0
i += 1 while i < 10
While mandatory needs end in Ruby.
Syntax example
do is optional and can be omitted.
So, it is not the case where pair do - end can be replaced with {}
When debugging shell scripts, I find it helpful to run with xtrace on:
-x xtrace Print commands and parameter
assignments when they are exe-
cuted, preceded by the value
of PS4.
For instance:
$ set -x
$ s='Say again?'
+ s='Say again?'
# Other commands that might mess with the value of $s
$ echo $s
+ echo Say 'again?'
Say again?
I know that Ruby has interactive debuggers such as pry and byebug, but I'm looking for something that will be easy to turn on for logging automated scripts.
I did find an xtrace gem, but it has something to do with a PHP format.
I also see there is a Tracer class and a TracePoint class which do seem to provide a way to print statements as they are executed. But I haven't found any way to print the value of variables (rather than just the variable name):
$ ruby -r tracer trace.rb
#0:/usr/local/Cellar/ruby/2.4.1_1/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:Kernel:<: return gem_original_require(path)
#0:trace.rb:1::-: s='Say again?'
#0:trace.rb:2::-: puts s
Say again?
I'd like to have the penultimate line read:
#0:trace.rb:2::-: puts 'Say again?'
Is this possible? Or is there a better way with Ruby?
I was able to build a module that more or less does what I'm looking for:
require 'pry'
=begin
We are always one line behind because the value of assignment comes
_after_ the trace is called. Without this, every assignment would look
like:
x = 1 #=> {:x=>nil}
It would be nice if the trace happened after assignment, but what can
you do?
=end
module Xtrace
# Only run the trace on the main file, not on require'd files.
# Possible room for expansion later.
#files = {$0 => Pry::Code.from_file($0)}
def Xtrace.print_trace
if #prev_line then
if #files[#path] then
line = #files[#path].around(#prev_line, 0).chomp
# When calling a method, don't make it look like it's being defined.
line.gsub!(/^\s*def\s*\b/, '') if #event == :call
values = []
#bind.local_variables.each do |v|
values << {v => #bind.local_variable_get(v)} if line =~ /\b#{v}\b/
end
STDERR.printf "%5s: %s", #prev_line, line
STDERR.printf " #=> %s", values.join(', ') unless values.empty?
STDERR.printf "\n"
end
end
end
#xtrace = TracePoint.trace(:line, :call) do |tp|
tp.disable
#bind=tp.binding
Xtrace.print_trace
# Other than the binding, everything we need to print comes from the
# previous trace call.
#prev_line = tp.lineno
#event=tp.event
#path=tp.path
tp.enable
end
# Need to print the trace one last time after the last line of code.
at_exit do
# It doesn't matter what we do in this last line. Any statement works.
# Also, it's a bit inconvenient that the disable command is itself traced.
#xtrace.disable
end
end
If you put it in a file named xtrace.rb and put in in your library load path, you can begin tracing by adding require 'xtrace'. It prints the line number of each line and method call executed, the actual code and the values of any local variable in the line. For a simple factorial function, the output might look like:
3: def factorial(n)
8: puts factorial(3)
3: factorial(n) #=> {:n=>3}
4: return 1 if n <= 1 #=> {:n=>3}
5: return n*factorial(n-1) #=> {:n=>2}
3: factorial(n) #=> {:n=>2}
4: return 1 if n <= 1 #=> {:n=>2}
5: return n*factorial(n-1) #=> {:n=>1}
3: factorial(n) #=> {:n=>1}
4: return 1 if n <= 1
6
For the moment, it only looks at local variables. It also only traces the executed file and not any loaded files. There's no way to enable or disable traces just yet. The trace begins when you require the module and ends when the execution does. Trace output goes to STDERR and the format is hardcoded.
If you use this module, watch out that you don't leak sensitive information such as passwords, API keys or PII.
I want to write a simple A+B program in ruby, but I have no idea how to work with the console.
Are you talking about gets?
puts "Enter A"
a = gets.chomp
puts "Enter B"
b = gets.chomp
c = a.to_i + b.to_i
puts c
Something like that?
Update
Kernel.gets tries to read the params found in ARGV and only asks to console if not ARGV found. To force to read from console even if ARGV is not empty use STDIN.gets
you can also pass the parameters through the command line. Command line arguments are stores in the array ARGV. so ARGV[0] is the first number and ARGV[1] the second number
#!/usr/bin/ruby
first_number = ARGV[0].to_i
second_number = ARGV[1].to_i
puts first_number + second_number
and you call it like this
% ./plus.rb 5 6
==> 11
There are many ways to take input from the users. I personally like
using the method gets. When you use gets, it gets the string
that you typed, and that includes the ENTER key that you pressed
to end your input.
name = gets
"mukesh\n"
You can see this in irb; type this and you will see the \n, which is the “newline” character that the ENTER key produces:
Type name = gets you will see somethings like "mukesh\n"
You can get rid of pesky newline character using chomp method.
The chomp method gives you back the string, but without the terminating newline. Beautiful chomp method life saviour.
name = gets.chomp
"mukesh"
You can also use terminal to read the input. ARGV is a constant defined in the Object class. It is an instance of the Array class and has access to all the array methods. Since it’s an array, even though it’s a constant, its elements can be modified and cleared with no trouble. By default, Ruby captures all the command line arguments passed to a Ruby program (split by spaces) when the command-line binary is invoked and stores them as strings in the ARGV array.
When written inside your Ruby program, ARGV will take take a command line command that looks like this:
test.rb hi my name is mukesh
and create an array that looks like this:
["hi", "my", "name", "is", "mukesh"]
But, if I want to passed limited input then we can use something like this.
test.rb 12 23
and use those input like this in your program:
a = ARGV[0]
b = ARGV[1]
if you want to hold the arguments from Terminal, try the following code:
A = ARGV[0].to_i
B = ARGV[1].to_i
puts "#{A} + #{B} = #{A + B}"
If you want to make interactive console:
#!/usr/bin/env ruby
require "readline"
addends = []
while addend_string = Readline.readline("> ", true)
addends << addend_string.to_i
puts "#{addends.join(' + ')} = #{addends.sum}"
end
Usage (assuming you put above snippet into summator file in current directory):
chmod +x summator
./summator
> 1
1 = 1
> 2
1 + 2 = 3
Use Ctrl + D to exit