In Python, we have something like print(f'{int(input()):,}') that separates numbers by commas. That is for example, if we provide the input of 70671891032 we get 70,671,891,032. Is there anything similar to this in Ruby (without the use of regex)?
Ruby's built-in string formatting doesn't have an option for a thousands separator.
If you don't want to use regular expressions, you could insert a separator every 3 characters from the right, e.g. via step:
input = 70671891032
string = input.to_s
(string.size - 3).step(1, -3) do |i|
string.insert(i, ',')
end
string
#=> "70,671,891,032"
I expect this is not what you were looking for, but it does convert a non-negative integer to a string of digits with thousands separators.
def commafy(n)
s = ''
loop do
break s if n.zero?
n, n3 = n.divmod(1000)
s[0,0] = (n.zero? ? ("%d" % n3) : (",%03d" % n3))
end
end
input = 70671891032
commafy(input)
#=> "70,671,891,032"
Related
Theoretical question
I'm trying to find new practical ways to convert integers into strings and the other way around.
I only know the .to_s ; .to_i ; .to_f methods and would like to know if there are other ways to do to it without writing + to put together the variables. For example:
var1 = 16
puts 'I\'m ' + var1.to_s + ' years old.'
In longer codes is getting tiring writing all this to just convert a integer to a string.
By the way I also found this Timer program here on Stack and the #{ is an example of what I'm trying to do. Adding an integer to a string without + and .to_s But I don't know how it works.
30.downto(0) do |i|
puts "00:00:#{'%02d' % i}"
sleep 1
end
Thank you in advance for the suggestions!
Ruby has a pretty powerful string interpolator feature using #{...} where that can contain fairly arbitrary Ruby code. The end result is always converted to a string using, effectively, to_s.
That is you can do this:
puts "00:00:#{'%02d' % i}"
Where that gets stringified and then interpolated.
This is roughly the same as:
i_str = '%02d' % i
puts "00:00:#{i_str}"
Where that is effectively:
i_str = '%02d' % i
puts "00:00:%s" % i_str
You could also combine that into a single operation:
puts "00:00:%02d" % i
Where you generally use interpolation or sprintf-style template strings, not both at the same time. It keeps your code cleaner since only one mechanism is in play.
The only reason .to_s is needed when doing concatenation is Ruby is very particular about "adding" together two things. x + y has a completely different outcome depending on what x and y are.
Consider:
# Integer + Integer (Integer#+)
1 + 2
# => 3
# Array + Array (Array#+)
[ 1 ] + [ 2 ]
# => [1,2]
# String + String (String#+)
"1" + "2"
# => "12"
Note that in each case it's actually a different method being called, and the general form of x + y is:
x.send(:+, y)
So it's actually a method call, and as such, each method may impose restrictions on what it can operate on by emitting exceptions if it can't or won't deal.
It's called string interpolation. For example:
puts "I\'m #{var1} years old."
The way it works is this:
You have to enclose the string in double quotes, not single quotes.
You put your variable inside this: #{}, e.g. "#{variable}".
This will always convert non-string variables into strings, and plug (i.e. interpolate) them into the surrounding string.
Are there any Ruby idioms or popular libraries for consolidating strings into a shell glob that would generate them? For example, given the strings,
abc1
abc2
abc3
I want to produce the string abc{1..3} or abc{1,2,3}. It's much like summarizing subnets in IP addressing.
I imagine a Rubyesque approach might involve sorting the strings and then building an array of their constituent characters, placing characters that don't overlap into nested arrays, recursively. However if there is something already out there, I'd rather not reinvent that wheel.
I borrowed the accepted solution to Finding common string in array of strings (ruby) and used a recursive algorithm:
def longest_common_substr(strings)
shortest = strings.min_by &:length
maxlen = shortest.length
maxlen.downto(0) do |len|
0.upto(maxlen - len) do |start|
substr = shortest[start,len]
return substr if strings.all?{|str| str.include? substr }
end
end
end
def create_glob(files)
return '' if files.compact.empty?
stub=longest_common_substr(files)
if stub.length == 0
expansion = files.uniq.join(',')
return '' if expansion == ''
return '{' + expansion + '}'
end
pre = []
post = []
files.each do |file|
i = file.index(stub)
pre << file[0, i]
post << file[i+stub.length..-1]
end
return create_glob(pre) + stub + create_glob(post)
end
That works well for your example:
puts create_glob(['abc1',
'abc2',
'abc3'
])
#=> abc{1,2,3}
It also covers more complicated cases such as variable prefixes:
puts create_glob(['first.abc1',
'second.abc2',
'third.abc3'
])
#=> {first,second,third}.abc{1,2,3}
And even missing values:
puts create_glob(['.abc1',
'abc',
'abc3'
])
#=> {.,}abc{1,,3}
Notice brace expansion might produce strings that are not files. For instance, the last example expands like this:
$ echo {.,}abc{1,,3}
.abc1 .abc .abc3 abc1 abc abc3
So you have to be just a little bit careful using the output.
I'm trying to build my own evaluator for mathematical expressions in ruby, and before doing that am trying to implement a parser to break the expression into a tree(of arrays). It correctly breaks down expressions with parenthesis, but I am having lots of trouble trying to figure out how to make it correctly break up an expression with operator precedence for addition.
Right now, a string like 1+2*3+4 becomes 1+[2*[3+4]] instead of 1+[2*3]+4. I'm trying to do the simplest solution possible.
Here is my code:
#d = 0
#error = false
#manipulate an array by reference
def calc_expr expr, array
until #d == expr.length
c = expr[#d]
case c
when "("
#d += 1
array.push calc_expr(expr, Array.new)
when ")"
#d += 1
return array
when /[\*\/]/
#d +=1
array.push c
when /[\+\-]/
#d+=1
array.push c
when /[0-9]/
x = 0
matched = false
expr[#d]
until matched == true
y = expr.match(/[0-9]+/,#d).to_s
case expr[#d+x]
when /[0-9]/
x+=1
else matched = true
end
end
array.push expr[#d,x].to_i
#d +=(x)
else
unless #error
#error = true
puts "Problem evaluating expression at index:#{#d}"
puts "Char '#{expr[#d]}' not recognized"
end
return
end
end
return array
end
#expression = ("(34+45)+(34+67)").gsub(" ","")
evaluated = calc #expression
puts evaluated.inspect
For fun, here's a fun regex-based 'parser' that uses the nice "inside-out" approach suggested by #DavidLjungMadison. It performs simple "a*b" multiplication and division first, followed by "a+b" addition and subtraction, and then unwraps any number left in parenthesis (a), and then starts over.
For simplicity in the regex I've only chosen to support integers; expanding each -?\d+ to something more robust, and replacing the .to_i with .to_f would allow it to work with floating point values.
module Math
def self.eval( expr )
expr = expr.dup
go = true
while go
go = false
go = true while expr.sub!(/(-?\d+)\s*([*\/])\s*(-?\d+)/) do
m,op,n = $1.to_i, $2, $3.to_i
op=="*" ? m*n : m/n
end
go = true while expr.sub!(/(-?\d+)\s*([+-])\s*(-?\d+)/) do
a,op,b = $1.to_i, $2, $3.to_i
op=="+" ? a+b : a-b
end
go = true while expr.gsub!(/\(\s*(-?\d+)\s*\)/,'\1')
end
expr.to_i
end
end
And here's a bit of testing for it:
tests = {
"1" => 1,
"1+1" => 2,
"1 + 1" => 2,
"1 - 1" => 0,
"-1" => -1,
"1 + -1" => 0,
"1 - -1" => 2,
"2*3+1" => 7,
"1+2*3" => 7,
"(1+2)*3" => 9,
"(2+(3-4) *3 ) * -6 * ( 3--4)" => 42,
"4*6/3*2" => 16
}
tests.each do |expr,expected|
actual = Math.eval expr
puts [expr.inspect,'=>',actual,'instead of',expected].join(' ') unless actual == expected
end
Note that I use sub! instead of gsub! on the operators in order to survive the last test case. If I had used gsub! then "4*6/3*2" would first be turned into "24/6" and thus result in 4, instead of the correct expansion "24/3*2" → "8*2" → 16.
If you really need to do the expression parsing yourself, then you should search for both sides of an expression (such as '2*3') and replace that with either your answer (if you are trying to calculate the answer) or an expression object (such as your tree of arrays, if you want to keep the structure of the expressions and evaluate later). If you do this in the order of precedence, then precedence will be preserved.
As a simplified example, your expression parser should:
Repeatedly search for all inner parens: /(([^)+]))/ and replace that with a call to the expression parser of $1 (sorry about the ugly regexp :)
Now all parens are gone, so you are looking at math operations between numbers and/or expression objects - treat them the same
Search for multiplication: /(expr|number)*(expr|number)/
Replace this with either the answer or encapsulate the two expressions in
a new expression. Again, depending on whether you need the answer now or
if you need the expression tree.
Search for addition: ... etc ...
If you are calculating the answer now then this is easy, each call to the expression parser eventually (after necessary recursion) returns a number which you can just replace the original expression with. It's a different story if you want to build the expression tree, and how you deal with a mixture of strings and expression objects so you can run a regexp on it is up to you, you could encode a pointer to the expression object in the string or else replace the entire string at the outside with an array of objects and use something similar to regexp to search the array.
You should also consider dealing with unary operators: "3*+3"
(It might simplify things if the very first step you take is to convert all numbers to a simple expression object just containing the number, you might be able to deal with unary operators here, but that can involve tricky situations like "-3++1")
Or just find an expression parsing library as suggested. :)
I'm trying to solve a problem where when given a string I convert each letter 13 places further in the alphabet. For example
a => n
b => o
c => p
Basically every letter in the string is converted 13 alphabet spaces.
If given the string 'sentence' i'd like it to convert to
'feagrapr'
I have no idea how to do it. I've tried
'sentence'.each_char.select{|x| 13.times{x.next}}
and I still couldn't solve it.
This one has been puzzling me for a while now, and I've given up trying to solve it.
I need your help
IMHO, there is a better way to achieve the same in idiomatic Ruby:
def rot13(string)
string.tr("A-Za-z", "N-ZA-Mn-za-m")
end
This works because the parameter 13 is hard-coded in the OP's question, in which case the tr function seems to be just the right tool for the job!
Using String#tr as TCSGrad suggests is the ideal solution.
Some alternatives:
Using case, ord, and chr
word = 'sentence'
word.gsub(/./) do |c|
case c
when 'a'..'m', 'A'..'M' then (c.ord + 13).chr
when 'n'..'z', 'N'..'Z' then (c.ord - 13).chr
else c
end
end
Using gsub and a hash for multiple replacement
word = 'sentence'
from = [*'a'..'z', *'A'..'Z']
to = [*'n'..'z', *'a'..'m', *'N'..'Z', *'A'..'M']
cipher = from.zip(to).to_h
word.gsub(/[a-zA-Z]/, cipher)
Note, Array#to_h requires Ruby 2.1+. For older versions of Ruby, use
cipher = Hash[from.zip(to)].
From here -> How do I increment/decrement a character in Ruby for all possible values?
you should do it like:
def increment_char(char)
return 'a' if char == 'z'
char.ord.next.chr
end
def increment_by_13(str)
conc = []
tmp = ''
str.split('').each do |c|
tmp = c
13.times.map{ |i| tmp = increment_char(tmp) }
conc << tmp
end
conc
end
Or close.
I need a string that is str_len characters long for testing.
What ways are there that are more elegant (and possibly faster) ways of building it than the following:
long_str = ''
(str_len + 1).times do
long_str << 'a'
end
It would be helpful if the algorithm could also randomise the content of the string (i.e. use any character).
Use the * method on the String class.
long_str = 'a' * 6
# => 'aaaaaa'
This produces a four letter long random string with the characters a to z.
charset=('a'..'z').to_a
srand(124931)
puts (0...4).map{ charset.to_a[rand(charset.size)] }.join
Remove or replace the srand(124931) with srand() before actually using this code.