Home > Blockchain >  ArgumentError in Ruby codewars 8 kyu kata
ArgumentError in Ruby codewars 8 kyu kata

Time:01-18

Question: Fake Binary: Given a string of digits, you should replace any digit below 5 with '0' and any digit 5 and above with '1'. Return the resulting string.

Can anyone explain why I got the error: ./lib/solution.rb:4:in `>': comparison of String with 5 failed (ArgumentError)

def fake_bin(s)
  arr = s.split("")
  
  arr.map! { |x| if x > 5 ? x = 1 : x = 0 }
  
  return arr.join("")
end

I actually already completed the solution with gsub so I don't need other suggestions, I'm just curious why I couldn't get this approach to work and what has caused this error.

I did try framing the if statement in a variety of ways but it made no difference.

CodePudding user response:

For map and map! it is important what the block returns, the assignment will not work.

Then you got a bit of a mixture between a if and a ternary statement.

Also you are comparing a string (input comes as a string, you split it into substrings) to an integer and this is where the error is coming from. Converting the string to an integer using to_i solves this problem.

And lastly you do not need to return a value. Ruby has implicit retuns where the last value in a method is returned.

So something like this should work:

def fake_bin(s)
  arr = s.split("")
  
  arr.map! { |x| x.to_i > 5 ? 1 : 0 }
  
  arr.join("")
end

If you want to shorten it, you can skip the intermediate assignments and just chain all the calls:

def fake_bin(s)
  s
    .chars
    .map { |x| x.to_i > 5 ? 1 : 0 }
    .join()
end

CodePudding user response:

The reason you got this error is because strings can't be compared with integers.

You split the string on every character, which gave you an array of each character in the string, something like so:

s = "12345"
arr = s.split("")
=> ["1","2","3","4","5"]

When you map through each of these, you're taking each element (for example, the first iteration would give you "1", but its in a STRING form) and then comparing it with 5, an integer. This comparison is illegal, and will throw an error.

Without redesigning your solution, you have three choices.

  1. Cast the String to an Integer (not recommended, you may get a Type Error that String cant be converted into an Integer)
  2. Cast the integer to a String (but look at number 3)
  3. Just use a string to compare(!)

Number three is the best. Your solution will look like so:

(PS: you had some small cosmetic errors which I've also fixed with regards to your ternary statement)

def fake_bin(s)
  arr = s.split("")
  
  arr.map! { |x| x > "5" ? "1" : "0" }
  
  return arr.join("")
end

Hope this helps.

  • Related