I want to make every other char in a string uppercase.
So far I have this code...
def task(s)
n = s.length
i = 1
while i < n
s[i] = s[i].upcase
if s[i] == " "
i = i
else
i += 2
end
end
s
end
This works fine however, I want my function to ignore spaces.
This is my current output
expected: "hElLo ThErE fRiEnD"
got: "hElLo tHeRe fRiEnD"
How can I implement this?
def upcase_every_so_many(str, freq)
return str if freq.zero?
str.gsub(/\p{L}/).with_index(1) { |c,i| (i % freq).zero? ? c.upcase : c }
end
str = "Now is the time for all good..."
puts "freq upcase_every_so_many(freq)"
(0..17).each { |freq| puts "%03s %020s" % [freq, upcase_every_so_many(str, freq)] }
freq upcase_every_so_many(freq)
0 Now is the time for all good...
1 NOW IS THE TIME FOR ALL GOOD...
2 NOw Is ThE tImE fOr AlL gOoD...
3 NoW is The TimE foR alL goOd...
4 Now Is thE timE for All gOod...
5 Now iS the tIme foR all gOod...
6 Now is The timE for alL good...
7 Now is tHe time fOr all goOd...
8 Now is thE time for All good...
9 Now is the Time for alL good...
10 Now is the tIme for all gOod...
11 Now is the tiMe for all gooD...
12 Now is the timE for all good...
13 Now is the time For all good...
14 Now is the time fOr all good...
15 Now is the time foR all good...
16 Now is the time for All good...
17 Now is the time for aLl good...
\p{L} matches each Unicode letter.
Note that I have used the form of String#gsub that returns an enumerator and that I have chained that enumerator to Enumerator#with_index.
Here's a variant of that method.
def upcase_every_so_many(str, freq)
return str if freq.zero?
enum = ([false]*(freq-1) + [true]).cycle
str.gsub(/\p{L}/) { |c| enum.next ? c.upcase : c }
end
upcase_every_so_many(str, 4)
#=> "Now Is thE timE for All gOod..."
See Array#cycle.
For freq = 4,
arr = [false]*(freq-1) << true
#=> [false, false, false, true]
enum = arr.cycle
#=> #<Enumerator: [false, false, false, true]:cycle>
enum.next
#=> false
enum.next
#=> false
enum.next
#=> false
enum.next
#=> true
enum.next
#=> false
... ad infinitum
Modifying your approach, you could instead split the string into individual characters (.split("")), then use map (a method which returns a new array created by modifying each item in an array) to first check if a character is a space, then if it should be uppercased (the up variable), and flips the value of up before returning the character. This gives us an array of characters which we can then join together with .join("").
def task(s)
up = false
s.split("").map do |char|
if char != " "
if up
char = char.upcase
end
up = !up
end
char
end.join("")
end
puts task("hello there friend")
Output:
hElLo ThErE fRiEnD
Building on this answer to your original question, here is an implementation that lets you pass in an upcase_frequency parameter - so you can capitalise every 2nd letter, or every 3rd letter, or every 100th letter, or whatever you want:
def task(s, upcase_frequency: 2)
upcase_counter = 1
s.split("").map do |char|
if char != " "
if upcase_counter % upcase_frequency == 0
char = char.upcase
end
upcase_counter += 1
end
char
end.join("")
end
puts task("hello there friend")
# => hElLo ThErE fRiEnD
puts task("hello there friend", upcase_frequency: 3)
# => heLlo TheRe fRieNd
I am trying to change numbers up to 100 from integers into words, but have run into some trouble, can anyone point out what is missing with my code:
def in_words(integer)
numWords = {
0=>"zero",
1=>"one",
2=>"two",
3=>"three",
4=>"four",
5=>"five",
6=>"six",
7=>"seven",
8=>"eight",
9=>"nine",
10=>"ten",
11=>"eleven",
12=>"twelve",
13=>"thirteen",
14=>"fourteen",
15=>"fifteen",
16=>"sixteen",
17=>"seventeen",
18=>"eighteen",
19=>"nineteen",
20=>"twenty",
30=>"thirty",
40=>"fourty",
50=>"fifty",
60=>"sixty",
70=>"seventy",
80=>"eighty",
90=>"ninety",
100=>"one hundred"
}
array = integer.to_s.split('')
new_array = []
numWords.each do |k,v|
array.each do |x|
if x = k
new_array.push(v)
end
end
end
new_array.join('')
end
Right now when I do:
inwords(0)
I get the following:
=>"zeroonetwothreefourfivesixseveneightnineteneleventwelvethirteenfourteenfiftee nsixteenseventeeneighteennineteentwentythirtyfourtyfiftysixtyseventyeightyninetyone hundred"
Edit
I noticed your code iterates through the array a lot of times and uses the = instead of the == in your if statements.
Your code could be more efficient using the Hash's #[] method in combination with the #map method.., here's a one-line alternative:
integer.to_s.split('').map {|i| numWords[i.to_i]} .join ' '
Also, notice that the integer.to_s.split('') will split the array into one-digit strings, so having numbers up to a hundred isn't relevant for the code I proposed.
To use all the numbers in the Hash, you might want to use a Regexp to identify the numbers you have. One way is to do the following (I write it in one line, but it's easy to break it down using variable names for each step):
integer.to_s.gsub(/(\d0)|([1]?\d)/) {|v| v + " "} .split.map {|i| numWords[i.to_i]} .join ' '
# or:
integer.to_s.gsub(/(#{numWords.keys.reverse.join('|')})/) {|v| v + " "} .split.map {|i| numWords[i.to_i]} .join ' '
# out = integer.to_s
# out = out.gsub(/(#{numWords.keys.reverse.join('|')})/) {|v| v + " "}
# out = out.split
# out = out.map {|i| numWords[i.to_i]}
# out = out.join ' '
Edit 2
Since you now mention that you want the method to accept numbers up to a hundred and return the actual number (23 => twenty three), maybe a different approach should be taken... I would recommend that you update your question as well.
def in_words(integer)
numWords = {
0=>"zero",
1=>"one",
2=>"two",
3=>"three",
4=>"four",
5=>"five",
6=>"six",
7=>"seven",
8=>"eight",
9=>"nine",
10=>"ten",
11=>"eleven",
12=>"twelve",
13=>"thirteen",
14=>"fourteen",
15=>"fifteen",
16=>"sixteen",
17=>"seventeen",
18=>"eighteen",
19=>"nineteen",
20=>"twenty",
30=>"thirty",
40=>"fourty",
50=>"fifty",
60=>"sixty",
70=>"seventy",
80=>"eighty",
90=>"ninety",
100=>"one hundred"
}
raise "cannot accept such large numbers" if integer > 100
raise "cannot accept such small numbers" if integer < 0
return "one hundred" if integer == 100
if integer < 20 || integer %10 == 0
numWords[integer]
else
[numWords[integer / 10 * 10], numWords[integer % 10]].join ' '
end
end
the integer / 10 * 10 makes the number a round number (ten, twenty, etc') because integers don't have fractions (so, 23/10 == 2 and 2 * 10 == 20). The same could be achieved using integer.round(-1), which is probably better.
It seems like all you're trying to do is find a mapping from an implicit hash
module NumWords
INT2STR = {
0=>"zero",
1=>"one",
2=>"two",
3=>"three",
4=>"four",
5=>"five",
6=>"six",
7=>"seven",
8=>"eight",
9=>"nine",
10=>"ten",
11=>"eleven",
12=>"twelve",
13=>"thirteen",
14=>"fourteen",
15=>"fifteen",
16=>"sixteen",
17=>"seventeen",
18=>"eighteen",
19=>"nineteen",
20=>"twenty",
30=>"thirty",
40=>"fourty",
50=>"fifty",
60=>"sixty",
70=>"seventy",
80=>"eighty",
90=>"ninety",
100=>"one hundred"
}
module_function
def in_words(integer)
INT2STR[integer]
end
end
The above code separates the hash definition from the method call so that the hash doesn't get recreated every time you call in_words.
You can also use Hash#fetch instead of Hash#[] as Andrey pointed out.
Your test whether x = k is your first problem (in two ways).
Firstly, if x = k means assign the value of k to x and then execute the if block if that value is true (basically anything other than false or nil).
What you should actually be testing is x == k which will return true if x is equal to k.
The second problem is that you converted your number into an array of string representation so you are comparing, for example, if "0" == 0. This won't return true because they are different types.
If you convert it to if x.to_i == k then your if block will be executed and you'll get:
> in_words(0)
=> "zero"
Then you get to move onto the next problem which is that you're looking at your number digit by digit and some of the values you are testing against need two digits to be recognised:
> in_words(10)
=> "zeroone"
You might be in looking at a different question then - or maybe that is the question you wanted answered all along!
Here's another way you might do it:
ONES_TO_TEXT = { 0=>"zero", 1=>"one", 2=>"two", 3=>"three", 4=>"four",
5=>"five", 6=>"six", 7=>"seven", 8=>"eight", 9=>"nine" }
TEENS_TO_TEXT = { 10=>"ten", 11=>"eleven", 12=>"twelve",
13=>"thirteen", 15=>"fifteen" }
TENS_TO_TEXT = { 2=>"twenty", 3=>"thirty", 5=>"fifty", 8=>"eighty" }
def in_words(n)
raise ArgumentError, "#{n} is out-of_range" unless (0..100).cover?(n)
case n.to_s.size
when 1 then ONES_TO_TEXT[n]
when 3 then "one hundred"
else
case n
when (10..19)
TEENS_TO_TEXT.key?(n) ? TEENS_TO_TEXT[n] : ONES_TO_TEXT[n]+"teen"
else
t,o = n.divmod(10)
(TENS_TO_TEXT.key?(t) ? TENS_TO_TEXT[t] : ONES_TO_TEXT[t]+"ty") +
(o.zero? ? '' : "-#{ONES_TO_TEXT[o]}")
end
end
end
Let's try it:
in_words(5) #=> "five"
in_words(10) #=> "ten"
in_words(15) #=> "fifteen"
in_words(20) #=> "twenty"
in_words(22) #=> "twenty-two"
in_words(30) #=> "thirty"
in_words(40) #=> "fourty"
in_words(45) #=> "fourty-five"
in_words(50) #=> "fifty"
in_words(80) #=> "eighty"
in_words(99) #=> "ninety-nine"
in_words(100) #=> "one hundred"
Here the increased complexity may not be justified, but this approach may in fact simplify the calculations when the maximum permitted value of n is much greater than 100.
def is_even?(n)
remainder_when_divided_by_2 = n % 2
if remainder_when_divided_by_2 == 0
return true
else
return false
end
end
def is_odd?(n)
return ! is_even?(n)
end
puts "1 is_even? #{is_even?(1)} - is_odd? #{is_odd?(1)}"
puts "2 is_even? #{is_even?(2)} - is_odd? #{is_odd?(2)}"
puts "3 is_even? #{is_even?(3)} - is_odd? #{is_odd?(3)}"
puts "4 is_even? #{is_even?(4)} - is_odd? #{is_odd?(4)}"
puts "5 is_even? #{is_even?(5)} - is_odd? #{is_odd?(5)}"
puts "6 is_even? #{is_even?(6)} - is_odd? #{is_odd?(6)}"
def is_even_and_divisible_by_five?(n)
remainder_when_divided_by_five = n % 5
if (remainder_when_divided_by_five == 0) && (is_even?(n) == true)
return true
else
return false
end
end
puts "5 is_even_and_divisible_by_five? #{is_even_and_divisible_by_five?(5)}"
puts "10 is_even_and_divisible_by_five? #{is_even_and_divisible_by_five?(10)}"
puts "15 is_even_and_divisible_by_five? #{is_even_and_divisible_by_five?(15)}"
puts "20 is_even_and_divisible_by_five? #{is_even_and_divisible_by_five?(20)}"
puts "25 is_even_and_divisible_by_five? #{is_even_and_divisible_by_five?(25)}"
puts "30 is_even_and_divisible_by_five? #{is_even_and_divisible_by_five?(30)}"
The problem was I had not called the method is_even_and_divisible_by_five in the puts commands at the bottom of the code. I called it is_even_and_divisble_by_5. Then in the if statement in the is_even_and_divisble_by_five method, I left of the (n) arguement from Is_even. Thank you all very much!
Even (divisible by two) and divisible by five also means "divisible by ten":
def is_even_and_divisible_by_five?(n)
n % 10 == 0
end
You called
is_even_and_divisible_by_5?
instead of
is_even_and_divisible_by_five?
Also is_even? function is undefined. I guess there was some mistake made with its defining or maybe even not-defining. So maybe when you defined is_even_and_divisible_by_five?(n) function there were some other errors and It was not defined too. Plus I think here is much easier solution:
def is_even_and_divisible_by_five?(n)
n % 5 == 0 && n.even?
end
In Ruby You don't have to use return all the time. You should use it quite rarely. The reason is ruby functions return last calculated value by default. And nearly everything is returning value in ruby, even blocks and If-Else statements. If you open irb console and try to do some code, for example:
a = 5
=> 5
Second line is what first line returns. You can do some experiments like this by your own with any type of conditions you like.
The name of your method is is_even_and_divisible_by_five?, not is_even_and_divisible_by_5?.
is_even? is not defined by itself
Here a shorter version of your method
def is_even_and_divisible_by_five? n
0 == n % 5 + n % 2
end
Is there a better method to display a number in hex with leading 0? I tried:
i.to_s(16)
but
2.to_s(16) #=> "2"
where I expect "02". I tried the print format:
"%02x" % i
which works for 2, but
"%02x" % 256 #=> "100"
where I want "0100". So I came up with this:
class Integer
def to_hex_string
("%0x" % self).size % 2 == 0 ? "%0x" % self : "%0#{("%0x" % self).size+1}x" % self
end
end
It works:
2.to_hex_string #=> "02"
256.to_hex_string #=> "0100"
It works also with class Bignumber, but it looks strange that such an easy request needs a trick like this. Any better idea?
for 2-digit hex values this works:
def to_hex(int)
int < 16 ? '0' + int.to_s(16) : int.to_s(16)
end
Yes, it bugs:
Let's try this:
class Integer
def to_hex_string
"0#{to_s(16)}"
end
end
class BigNumber
def to_hex_string
"0#{to_s(16)}"
end
end
class String
def to_hex_string
self.unpack('H*').first
end
def to_bytes_string
unless self.size % 2 == 0
raise "Can't translate a string unless it has an even number of digits"
end
raise "Can't translate non-hex characters" if self =~ /[^0-9A-Fa-f]/
[self].pack('H*')
end
def to_bignum
self.bytes.inject { |a,b| (a << 8) + b }
end
end
p a="ff"*192 # => "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
p bytestring=a.to_bytes_string # => "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
p bytestring.to_hex_string # => "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
p biga=a.to_bytes_string.to_bignum # => 2410312426921032588580116606028314112912093247945688951359675039065257391591803200669085024107346049663448766280888004787862416978794958324969612987890774651455213339381625224770782077917681499676845543137387820057597345857904599109461387122099507964997815641342300677629473355281617428411794163967785870370368969109221591943054232011562758450080579587850900993714892283476646631181515063804873375182260506246992837898705971012525843324401232986857004760339316735
And the BUG is here:
p biga.to_hex_string # => "0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
Where does this 0 come from????
What is even more strange is my complicated solution is working:
p ("%0x" % biga).size % 2 == 0 ? "%0x" % biga : "%0#{("%0x" % biga).size+1}x" % biga # => "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
Maybe a bug in "0#{to_s(16)}"?
Use "%.2x", where 2 is the amount of digits you want.
"%.2x" % 0 # => "00"
"%.2x" % 15 # => "0f"
"%.2x" % 255 # => "ff"
This was the first hit on Google when I was just trying to solve this. I had to find a couple of other posts to finish up my solution but I think this is clean.
class Fixnum
def to_hex(bits)
rjust = (bits/4 + (bits.modulo(4)==0 ? 0 : 1))
"0x" + self.to_s(16).rjust(rjust, "0")
end
end
You are making this way too complicated. If you want to print an integer in hexadecimal with a leading zero, then it is just
class Integer
def to_hex_string
"0#{to_s(16)}"
end
end
2.to_hex_string # => 02
256.to_hex_string # => 0100
I am new to Ruby and I am trying to write a program which convert Roman numerals to numbers.
This is what I did so far:
roman_numbers = {"M" => 1000, "D" => 500, "C" => 100, "L" => 50, "X" => 10, "V" => 5, "I" => 1}
number_by_user = "MCMXCIX"
singlenum = number_by_user.split(//).reverse!
l = singlenum.length
result =0
result = roman_numbers[singlenum[0]]
puts result
for i in 0..l-1
if roman_numbers.key?(singlenum[i])
**if (roman_numbers[singlenum[i]] > roman_numbers[singlenum[i+1]])** #gives error
result = result - roman_numbers[singlenum[i+1]]
elsif (roman_numbers[singlenum[i]]== roman_numbers[singlenum[i+1]] || **roman_numbers[singlenum[i]] < roman_numbers[singlenum[i+1]])** #gives error
result = result + roman_numbers[singlenum[i+1]]
end
puts roman_numbers[singlenum[i]]
else
puts "One of the values are not roman"
break
end
end
puts "The number is: " , result
but it gives me the following error (see the line with comment):
:in `>': comparison of Fixnum with nil failed (ArgumentError)
You have an off-by-one error. Arrays are 0 indexed. Your singlenum.length in this case is 7, but in your for loop, you go up to 6, then try to reference singlenum[7] to compare to singlenum[6]. singlenum[7] is nil, so it doesn't understand the < operator.
Marc did a good job of explaining where the error was in your code. However, such an error should never have occurred in the first place, since in Ruby, all collections already know how to iterate over themselves: you don't have to do that, so you can never even make such a mistake!
Here's an example of how one might implement the same algorithm in more idiomatic Ruby:
numerals = {
'M' => 1000,
'D' => 500,
'C' => 100,
'L' => 50,
'X' => 10,
'V' => 5,
'I' => 1
}
num = 'MCMXCIX'
(num.chars.map(&numerals.method(:[])) << 0).each_cons(2).inject(0) {|a, (n1, n2)|
if n1 < n2 then a - n1 else a + n1 end
}
See? No loops. No indices. You cannot make an off-by-one error even if you tried!
Bonus: actually, the above snippet does contain a piece of code to prevent an off-by-one error, albeit one at a much higher semantic level. Can you find it?