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?
Related
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
Learning programming so sorry for a beginner question! Here I have a code that works in my sublime text editor but raises an exception on Coderbyte, which from what I know uses Ruby 1.8.7. I suspect it might have to do with the different versions of Ruby. Would be helpful to understand what is going wrong. Thanks for replying!
Exception raised is:
(eval):9: undefined method `keys' for []:Array (NoMethodError) from (eval):4:in `each' from (eval):4:in `LetterCountI' from (eval):23
def LetterCountI(str)
str = str.split
repeating_letters = []
str.each do |word|
word = word.split("")
letters = Hash.new(0)
word.each { |letter| letters[letter] += 1 }
selected_letters = letters.select { |key, value| value > 1 }
repeating_letters << selected_letters.keys.length
end
if (repeating_letters.select {|l| l >= 1}).empty?
return -1
else
max = repeating_letters.max
p repeating_letters
return str[repeating_letters.index(max)]
end
end
Yes, it's the versions. In Ruby 1.8.7 hash.select returns an Array, which has no keys method. In later versions select returns a Hash.
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?!
Can anyone please help a relatively new person of ruby to see why I am getting this no method error? It would be much appreciated!
def comp_block
only_user_valued = #winning_propositions.map { |each_hash| each_hash.select { |key, value| value == #user_sign } }
count_of_each = only_user_valued.map { |count_the_items_in_hash| count_the_items_in_hash.count }
index_array = count_of_each.each_with_index.select { |num, index| num == 2 }.map { |index_spot| index_spot[1] }
if index_array.empty? == true
random_move
else
#nil_valued_values_array = []
#nil_valued_array_true_false = []
index_array.each do |element|
#nil_valued_values_array += [#winning_propositions[element].select { |key, value| value == nil }]
#nil_valued_array_true_false += [#nil_valued_values_array.empty?]
end
nil_value = #nil_valued_values_array.delete({})
move = nil_value[0].keys[0]
if #nil_valued_array_true_false == [false] || #nil_valued_array_true_false == [true, false] || #nil_valued_array_true_false == [false, true]
#possible_places[move] = #comp_sign
#changes the winning prop values in parallel
list_of_matching_arrays=#winning_propositions.select { |key, value| key.to_s.match(move.to_s) }
list_of_matching_arrays.each do |change_hash_value|
change_hash_value[move] = #comp_sign
end
puts #comp_name + " made the move: #{move}"
display_game_board
puts "Here I am defending/BLOCKED!!!!!!"
else #nil_valued_array_true_false == [true] || #nil_valued_array_true_false == [true, true]
random_move
end
end
end
Well, obviously either nil_value or nil_value[0].keys is nil. Looking at the two lines of code:
nil_value = #nil_valued_values_array.delete({})
move = nil_value[0].keys[0]
The most obvious reason is that #nil_valued_values_array.delete({}) does not find an empty hash to delete, thus returns nil, or if it does find one, it returns an empty hash.
Well, this isn't exactly a fix (since you've got a bunch of code, not sure which things are happening externally), but you should add some debugging statements.
Look here:
move = nil_value[0].keys[0]
If either nil_value or keys are nil, you're going to get that error obviously. I suggest you print their values and see which one is null:
puts "<<<<< NIL_VALUE: #{nil_value}"
puts "<<<<< NIL_VALUE[0]: #{nil_value[0]}"
puts "<<<<< NIL_VALUE[0].KEYS: #{nil_value[0].keys}"
so on and so forth.
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