palindrome check in ruby - ruby

Why is this code giving wrong output for this input ?
def palindrome?(str)
str.delete('^a-zA-Z')
str.downcase
str == str.reverse
end
INPUT = "A man, a plan, a canal -- Panama"
OUTPUT = Failure/Error: palindrome?("A man, a plan, a canal -- Panama").should be_true, "Incorrect results for input: \"A man, a plan, a canal -- Panama\""
Incorrect results for input: "A man, a plan, a canal -- Panama"
# spec.rb:7:in `block (2 levels) in <top (required)>'
# ./lib/rspec_runner.rb:36:in `block in run_rspec'
# ./lib/rspec_runner.rb:32:in `run_rspec'
# ./lib/rspec_runner.rb:23:in `run'
# lib/graders/weighted_rspec_grader.rb:6:in `grade!'
# ./grade:31:in `<main>'

The delete and downcase methods on Strings do not modify the String itself, they return a changed copy. If you want to modify the receiver, use the bang variants:
str.delete!('[^a-zA-Z]')
str.downcase!
on second thoughts, don't do this, because horrible things like this happen:
string = "hello123"
palindrome?(string)
string #=> "OLLEH"
Instead, make a copy of the argument and modify that:
def palindrome?(arg)
str = arg.dup
str.delete!('[^a-zA-Z]')
str.downcase!
str == str.reverse
end

How to find the total number of palindromes for a string
class String
def palindrome?
self == self.strip.reverse
end
def sub_str_arr
(0..self.length).inject([]){|ai,i|
(1..self.length - i).inject(ai){|aj,j|
aj << self[i,j]
}
}
end
def num_palindromes
return -1 if self.length > 100000000
self.sub_str_arr.reject!{|item| item if item.length < 2 || !item.palindrome?}.size
end
end
puts "dabadbadbadbdbadbadbdabdbadbadbadbadbadadadbdbdbdbadbdabadbadbdbadbabdabdbbdabdabdbadba".num_palindromes

Related

"NoMethodError" in Ruby

Been trying to solve this Codewars problem with Ruby (https://www.codewars.com/kata/57061b6fcb7293901a000ac7/train/ruby) but it keeps giving me this error and I don't know the reason.
main.rb:10:in `head_smash': undefined method `each' for "":String (NoMethodError)
from main.rb:80:in `block in <main>'
from /runner/frameworks/ruby/cw-2.rb:55:in `block in describe'
from /runner/frameworks/ruby/cw-2.rb:46:in `measure'
from /runner/frameworks/ruby/cw-2.rb:51:in `describe'
from main.rb:17:in `<main>'
My code to solve this problem is this one:
def head_smash(arr)
arr1 = []
if arr == []
return 'Gym is empty'
elsif arr.is_a?(Integer) == true
return 'This isn\'t the gym!!'
else
arr.each do |i|
arr1.append(i.gsub(/O/, ' '))
end
end
return arr1
end
Thanks!
It is probably this test (see line #64 in the test for that exercise) that makes your code fail:
Test.assert_equals(head_smash(''),'Gym is empty')
In that test, the input is an empty String but your code doesn't check for string types and at least handles empty Strings. Instead, your code calls arr.each when arr is a string.
A very simple approach to fix this specific issue would be to change the first condition
if arr == []
to any of the following
if arr == [] || arr == ''
if [[], ''].include?(arr)
if arr.respond_to?(:empty?) && arr.empty?

Hash keeps failing to iterate

I am trying to iterate through a folder, select all the files that end in .bowtie.txt, count the number of lines, and then write the number of lines with the filename it came from, to a hash (or even better an external csv but a hash will do for now). I was provided with this solution
Dir['/Volumes/.../*.bowtie.txt'].inject({}) do |memo, file|
memo[file] = File.readlines(file).select do |line|
line =~ /^[0-9]+\s*(\+|\-)/ # only those, matching
end.count
puts memo
end
however this has to odd behaviour of selecting a file, then giving me one hash before it fails as follows:
Me:~ me$ ruby /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb
{"/Volumes/SeagateBackupPlusDriv/SequencingRawFiles/TumourOesophagealOCCAMS/SequencingScripts/3finalcounts/SLX-9279.GoodDysplasia.FSeqA_BEST2_NEW_0204_LessThan10PCent_HGD_.fq.gz.bowtie.txt"=>31312}
/Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:5:in `block in <main>': undefined method `[]=' for nil:NilClass (NoMethodError)
from /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:4:in `each'
from /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:4:in `inject'
from /Users/me/Desktop/SequencingScripts/Plots/GeneralScripts/DistinctPositions.rb:4:in `<main>'
when I don't use puts memo I don't get an error but I also don't get any output to the terminal. How do I get what I want?
In order to use inject in this context, you need to return your memo object at the end. So in your example, that would look like:
Dir['/Volumes/.../*.bowtie.txt'].inject({}) do |memo, file|
memo[file] = File.readlines(file).select do |line|
line =~ /^[0-9]+\s*(\+|\-)/ # only those, matching
end.count
puts memo
memo
end
Here's a contrived example to illustrate the same error & resolution:
[1] pry(main)> [1, 2, 3].inject({}) { |hash, num| hash[num] = 1 }
NoMethodError: undefined method []= for 1:Fixnum
[2] pry(main)> [1, 2, 3].inject({}) { |hash, num| hash[num] = 1; hash }
=> {1=>1, 2=>1, 3=>1}
if you use inject your block should ALWAYS return updated memo in the last line. In your case during the second iteration memo is equal to last line so to the result of puts memo
Dir['/Volumes/.../*.bowtie.txt'].inject({}) do |memo, file|
memo[file] = File.readlines(file).select do |line|
line =~ /^[0-9]+\s*(\+|\-)/ # only those, matching
end.count
puts memo
memo
end

Error in sample ruby program to swap element in an array

I created a sample ruby program to swap elements in an array
class Swap
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
array = [1,2,3]
array.swp(1,2)
puts array
end
I am getting the following error
NoMethodError: private method `swp' called for [1, 2, 3]:Array
from (irb):77:in `<class:Swap>'
from (irb):71
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:8:in `start'
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Please help to fix it.
UPDATE
I tried the same program with dynamic array input like this:
class Swap
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
puts "enter the array elements "
input = gets.chomp
ary = []
while input != 'fin'
ary << input.to_i
input = gets.chomp
end
puts ary
puts "enter the elements to be swapped"
a=gets
b=gets
s=Swap.new
ary = ary.s.swp(a,b)
puts ary
Now the output error is like this:
enter the array elements
1
2
3
4
5
fin
enter the positions to be swapped
1
2
NoMethodError: private method `s' called for [0, 1, 2, 3, 4, 5]:Array
from (irb):17:in `<class:Swap>'
from (irb):1
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
array.class = Array, you should add swp method for Array class.
class Array
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
array = [1,2,3]
array.swp(0,1) #The array index start from 0, not 1
puts array.inspect
=> [2, 1, 3]
Update:
class Array
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
puts "enter the array elements "
ary = []
input = 0
while 1
input = gets.chomp
if input != 'fin'
ary << input.to_i
else
break
end
end
puts "enter the positions to be swapped"
a=gets.to_i
b=gets.to_i
ary.swp(a,b)
puts ary.inspect
I don't like editing classes like that, for example if there's another class in the ancestor tree that implements the actual swp method (for any reason) and you implemented yours, and you try to use the actual documented one, you'll find unexplained behaviour, and it might be uneasy to figure out why it's behaving like that, beacuse your method is hiding, it's more maintainable if you add your methods to the ancestry tree using a module and then including it to the class.
module Swappable
def swp(a, b)
# method goes here
end
end
Then in another file you would do
class Array
include Swappable
end
This way when you call Array.ancestors you'd see your module
Array.ancestors
=> [Array, Swappable, ....]
And when you try something like
Array.instance_method(:swp).owner
you'll get Swappable, while an open class editing would return Array
This is just my oppinion on this matter, you can pick whatever works for you.
You can try the following code blog for take input an array and swap with two positions.
Here I initialize Swap class with an input array and then pass two swap position.
Main Class
class Swap
def initialize(array)
#array = array#[1,2,3,4,5]
end
def swp(a,b)
#array[a],#array[b] = #array[b],#array[a]
#array
end
end
Take Input for array
puts "ArrayInput :: Enter numbers separated by spaces, press 'Enter' to finish:"
array = gets
array = array.split(" ")
Take Input for swap positions
puts "SwapInput:: For FirstPosition, press 'Enter' to finish:"
first_position = gets.to_i
puts "SwapInput:: For SecondPosition, press 'Enter' to finish:"
second_position = gets.to_i
Initialize Swap Class
swap = Swap.new(array)
array = swap.swp(first_position, second_position)
puts "Array after swap:"
puts array

Comparing with nil error in quicksort

I'm trying to write quicksort in Ruby, but I get an error that says:
qsort.rb:43:in `<': comparison of Fixnum with nil failed (ArgumentError)
from qsort.rb:43:in `block in dist'
from qsort.rb:42:in `each'
from qsort.rb:42:in `dist'
from qsort.rb:32:in `sort'
from qsort.rb:34:in `sort'
from qsort.rb:53:in `<main>'
This is my code:
#!usr/bin/ruby
class QArray
#data = []
#pvalue
#less
#more
def initialize(arr = [])
#data = arr
#pvalue = #data[0] unless #data.empty?
end
#these methods are so I can treat a QArray like a regular array
def push(value)
#data.push value
end
def empty?
#data.empty?
end
def single?
return #data.size == 1
end
def print
puts #data
end
def sort
puts "starting the sort with an array of #{#data}"
dist unless #data.empty?
#less.sort unless #less.empty? || #less.single?
#more.sort unless #more.empty? || #more.single?
#data = #less + #more #combine the two arrays again
end
def dist
#distributes values into subarrays
#less = QArray.new
#more = QArray.new
#data.each {|e|
if (e < #pvalue)
#less.push e
else #includes both equals and greater than
#more.push e
end
}
end
end
arr = QArray.new ([1,5,6,7,9,23,43,2,4,6])
arr.sort
arr.print
I'm guessing that this is related to e being nil in the block. However, this shouldn't happen, because I check whether the array is empty before I call dist.
Why do I get this error, and what can I do to fix it?
You create new QArrays in dist.
You initialize #pvalue on QArray creation, but they're empty when created in dist.
In dist you then try to use #pvalue, which is nil, because you create the array empty and only then add values to it, never updating the uninitialized #pvalue value.
Unrelated, but what are those class instance variables at the top of QArray for?!

How can I keep track of my stack trace height for debugging purposes?

I want my code to do the following:
def debug (message)
puts message.rjust(message.length + (stack_trace-1 * 2)) # -1 for the call to debug
end
def a
debug "in a"
b
debug "end a"
end
def b
debug "in b"
c
debug "end b"
end
def c
debug "in c"
meaningful_work
debug "end c"
end
Output:
in a
in b
in c
end c
end b
end a
I've done this before in PHP, like this:
function echon($string){
$nest_level = count(debug_backtrace()) - 1; // minus one to ignore the call to *this* function
echo str_repeat(" ", $nest_level) . $string . "\n";
}
As far as my google-fu can tell, there isn't a Ruby equivalent to debug_backtrace. I don't want to modify the calls of all the numerous methods in the code base I am working in to pass along a backtrace - that is needlessly cumbersome and hard to revert.
Is there some global I can use to keep track here?
Simply use Kernel#caller with .length. caller(0).length will give you the current stack depth.
Example:
irb(main):001:0> caller(0)
=> ["(irb):1:in `irb_binding'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86:in `eval'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86:in `evaluate'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/context.rb:380:in `evaluate'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:492:in `block (2 levels) in eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:624:in `signal_status'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:489:in `block in eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:247:in `block (2 levels) in each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:233:in `loop'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:233:in `block in each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:232:in `catch'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:232:in `each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:488:in `eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:397:in `block in start'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:396:in `catch'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:396:in `start'", "/usr/bin/irb:12:in `<main>'"]
irb(main):002:0> caller(0).length
=> 17
Here is one way to implement #nneonneo's excellent suggestion.
Code
INDENT = 2
def debug(msg=nil)
#prev_arr_size ||= 1
#arrived ||= false
arr = caller(1)
indent = ' '*(arr.size-2)*INDENT
if msg
puts indent + msg
return
end
meth, call_meth = method_str(arr[0]), method_str(arr[1])
entering = (#prev_arr_size==arr.size) ? !#arrived : #prev_arr_size < arr.size
msg1, msg2 = entering ? ["in ", "called from "] : ["end", "returning to"]
puts indent + "%s %s, %s %s" % [msg1, meth, msg2, call_meth]
#prev_arr_size = arr.size
#arrived = !#arrived
end
def method_str(str)
file, _, meth = str.partition(/:.*?in\s+/)
"#{meth[1..-2]} (#{file})"
end
Example
def a
debug
# frivolous work
b
debug
end
def b
debug
c
x = 5
debug "It seems that x is now #{x}"
# more frivolous work
c
debug
end
def c
debug
# meaningful_work
debug
end
a
#=> in a (t.rb), called from <main> (t.rb)
# in b (t.rb), called from a (t.rb)
# in c (t.rb), called from b (t.rb)
# end c (t.rb), returning to b (t.rb)
# It seems that x is now 5
# in c (t.rb), called from b (t.rb)
# end c (t.rb), returning to b (t.rb)
# end b (t.rb), returning to a (t.rb)
# end a (t.rb), returning to <main> (t.rb)

Resources