I changed my integers to strings, but #gsub only recognizes 0-9 - ruby

I'm self-learning Ruby, and one assignment is to make a Caesar cipher.
Using #gsub, I've been able to change my letters to integers ('c' => 2), shift them, then change the new integers to strings (2 => "2").
I've hit a wall, and the Ruby documentation isn't helping. When I try to #gsub the strings back to letters ("2" => 'c') it only recognizes 0-9. Everything after that is just a concatenation of those numbers ("12" => 'bc' instead of => 'l').
Why does Ruby do this, and how can I fix it?
Thanks for your help guys.
code: (I know it's sloppy beginner's code; I will try to edit it after it passes)
def convert_to_integer
puts "What would you like to encode?"
words = gets.chomp
words = words.split("")
words.map { |words| words.gsub!(/[a-z]/, 'a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'e' => 4, 'f' => 5, 'g' => 6, 'h' => 7, 'i' => 8, 'j' => 9, 'k' => 10, 'l' => 11, 'm' => 12, 'n' => 13, 'o' => 14, 'p' => 15, 'q' => 16, 'r' => 17, 's' => 18, 't' => 19, 'u' => 20, 'v' => 21, 'w' => 22, 'x' => 23, 'y' => 24, 'z' => 25)
}
integer = words.map! { |letter| letter.to_i }
return integer
end
def shift_left(integer, number = 0)
puts "How many letters (to the left) would you like to shift it?"
number = gets.to_i
integer.map! { |n| n - number }
return integer
end
def convert_to_letter(integer)
integer.map! { |integer| integer.to_s }
integer.map! { |n| n.gsub(/[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]/, '0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd', '4' => 'e', '5' => 'f', '6' => 'g', '7' => 'h', '8' => 'i', '9' => 'j', '10' => 'k', '11' => 'l', '12' => 'm', '13' => 'n', '14' => 'o', '15' => 'p', '16' => 'q', '17' => 'r', '18' => 's', '19' => 't', '20' => 'u', '21' => 'v', '22' => 'w', '23' => 'x', '24' => 'y', '25' => 'z')
}
print integer
end
convert_to_letter(shift_left(convert_to_integer))

You don't need to do a gsub there. gsub is normally used to replace parts of a bigger string. You want to replace the whole thing.
This should do the trick:
def convert_to_letter(integers)
replacements = {0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd', 4 => 'e',
5 => 'f', 6 => 'g', 7 => 'h', 8 => 'i', 9 => 'j', 10 => 'k',
11 => 'l', 12 => 'm', 13 => 'n', 14 => 'o', 15 => 'p', 16 => 'q',
17 => 'r', 18 => 's', 19 => 't', 20 => 'u', 21 => 'v', 22 => 'w',
23 => 'x', 24 => 'y', 25 => 'z'
}
integers.map{|x| replacements[x]}.join
end
Also, be careful with destructive operations (map! here). You may run into undesired side-effects (for example, some arrays will change when you think they shouldn't).

It's easier and faster to use lookups:
#letter_to_number = ('a'..'z').zip(0..25).to_h
#number_to_letter = (0..25).zip('a'..'z').to_h
def convert_to_integers(letters)
letters.map{|l| #letter_to_number[l]}
end
def convert_to_letters(numbers)
numbers.map{|n| #number_to_letter[n]}
end
There's also a shortcut that combines the lookups and combines the methods.
#convert = (('a'..'z').zip(0..25) + (0..25).zip('a'..'z')).to_h
def convert(objects)
objects.map{|o| #convert[o]}
end

That's not how regular expressions work. "12".gsub(/[12]/, '12' => 'm') does not produce "m". That code says to find any occurrence of "1" or "2", and replace it according to the following rule: "12" gets replaced with "m", and, implicitly, anything else gets replaced with nothing. Both the "1" and the "2" are occurrences of "1" or "2", but neither of them are "12", so they both get replaced with nothing. Thus the above results in just the empty string.
In fact gsub and regular expressions are not really ideal for this problem. You could just do this:
def char_to_int(char)
char.ord - 97
end
def int_to_char(int)
(int + 97).chr
end
def caesar(string, shift)
string.split(" ").map do |word|
word.split("").map do |letter|
int_to_char((char_to_int(letter) - shift) % 26)
end.join
end.join(" ")
end

Related

Change Table Size Prawn

Hi guys I'm doing a ruby ​​report using prawn! how can I change the size of the table?
Code:
require "prawn"
require "prawn/table"
logo=Dir.pwd+"/logo.jpg"
arr = ['a', 'aa', 'aaa', 'ddd', 'eee', 'fff']
arr2 = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff']
arr3 = ['a', 'b', 'c', 'd', 'e', 'f']
Prawn::Document.generate("rapportino.pdf") do
move_down 10
image logo,:width=>540,:height=>60
move_down 30
text "Ragione Sociale: "+ARGV[0]
move_down 30
text "Nome Cantiere: "+ARGV[1]
move_down 30
text "Note: "+ARGV[2]
move_down 30
table([
["Articolo - Risorsa", "Descrizione", "Quantita"],
*[arr, arr2, arr3]
.transpose
])
end
You can pass options hash as a arg to table() specifying the columns width or a width.
options = {column_widths:{ 0 => 125, 1 => 100 }, width: 225}
In your example:
options = {column_widths:{ 0 => 125, 1 => 100 }, width: 225}
arr = ['a', 'aa', 'aaa', 'ddd', 'eee', 'fff']
arr2 = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff']
arr3 = ['a', 'b', 'c', 'd', 'e', 'f']
Prawn::Document.generate("rapportino.pdf") do
move_down 10
image logo,:width=>540,:height=>60
move_down 30
text "Ragione Sociale: "+ARGV[0]
move_down 30
text "Nome Cantiere: "+ARGV[1]
move_down 30
text "Note: "+ARGV[2]
move_down 30
table([
["Articolo - Risorsa", "Descrizione", "Quantita"],
*[arr, arr2, arr3]
.transpose
],options)
end

Converting a multi-level hash into a single hash

I have a source hash:
a = {'1' => 'A',
'2' => 'B',
'3' => 'C',
'4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' }},
'10' => {'11' => 'H'}}
I need to construct a method to make it a flat hash (single hash). The result should look like:
a = {'1' => 'A', '2' => 'B', '3' => 'C', '5' => 'D', '6' => 'E', '8' => 'F', '9' => 'G', '11' => 'H'}
I tried with merge, deep_merge, each_with_object, and recursion, but they did not give proper results.
Appreciate any help.
a = {'1' => 'A',
'2' => 'B',
'3' => 'C',
'4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' }},
'10' => {'11' => 'H'}}
# recursive detect value is Hash or not
compact_hash = ->(hh, h0={}) {
hh.reduce(h0) do |h, (k, v)|
if v.is_a? Hash
compact_hash[v, h]
else
h[k] = v
h
end
end
}
puts compact_hash[a]
Many thanks to #cary, I knew how to do one-line without ; and remove h.
compact_hash = ->(hh, h0={}) {
hh.each_with_object(h0) { |(k, v), h | v.is_a?(Hash) ? compact_hash[v, h] : h[k] = v }
}
h = { '1' => 'A', '2' => 'B', '3' => 'C',
'4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' } },
'10' => { '11' => 'H'} }
hh = h.dup
loop do
g = hh.select { |_,v| v.is_a? Hash }
break hh if g.empty?
g.keys.each { |k| hh.delete(k) }
g.values.each { |f| hh.update(f) }
end
#=> {"1"=>"A", "2"=>"B", "3"=>"C", "5"=>"D", "6"=>"E", "11"=>"H", "8"=>"F", "9"=>"G"}
This does not mutate h:
h #=> { "1"=>"A", "2"=>"B", "3"=>"C",
# "4"=>{"5"=>"D", "6"=>"E", "7"=>{"8"=>"F", "9"=>"G"}},
# "10"=>{"11"=>"H"}}
The antepenultimate line could be replaced by the following.
g_keys = g.keys
hh.delete_if { |k| g_keys.include?(k) }
I don't know which would be the more efficient.
a = {'1' => 'A',
'2' => 'B',
'3' => 'C',
'4' => { '5' => 'D', '6' => 'E', '7' => { '8' => 'F', '9' => 'G' }},
'10' => {'11' => 'H'}}
def flatten_hash(hash)
hash.each_pair.reduce({}) do |h, (k, v)|
v.is_a?(Hash) ? h.merge(flatten_hash(v)) : h.merge(k => v)
end
end
# pry(main)> flatten_hash(a)
#=> {"1"=>"A", "2"=>"B", "3"=>"C", "5"=>"D", "6"=>"E", "8"=>"F", "9"=>"G", "11"=>"H"}

Print random value from selected key in python

I want to print a random value from a selected key. Inside the code are comments that explain the code.
cases = {
'wildfire' : {
'blue' : ['1', '2', '3', '4', '5'],
'purple' : ['6', '7', '8', '9', '10'],
'pink' : ['11', '12', '13', '14', '15'],
'red' : ['16', '17', '18', '19', '20'],
'knives' : ['k', 'b', 'f']
},
'phoenix' : {
'blue' : ['1', '2', '3', '4', '5'],
'purple' : ['6', '7', '8', '9', '10'],
'pink' : ['11', '12', '13', '14', '15'],
'red' : ['16', '17', '18', '19', '20'],
'knives' : ['k', 'b', 'f']
},
'gamma' : {
'blue' : ['1', '2', '3', '4', '5'],
'purple' : ['6', '7', '8', '9', '10'],
'pink' : ['11', '12', '13', '14', '15'],
'red' : ['16', '17', '18', '19', '20'],
'knives' : ['k', 'b', 'f']
},
'chroma' : {
'blue' : ['1', '2', '3', '4', '5'],
'purple' : ['6', '7', '8', '9', '10'],
'pink' : ['11', '12', '13', '14', '15'],
'red' : ['16', '17', '18', '19', '20'],
'knives' : ['k', 'b', 'f']
},
}
#First keys in dictionary are cases which can be selected by user
#The keys in cases dictionary are scaled from common to uncommon (top to bottom)
#Values in the cases dictionary are the skins.
case_keys = 10
#case_keys are used to open cases
while case_keys >0:
resp=raw_input("Which case would you like to open? ")
for i in cases:
if resp == i:
chance = random.randint(1, 100)
"""HELP HERE. The skins are classed by rarity. E.g blue is common
but purple is more rare than blue and so forth. E.g blue is assigned to 25,
purple to 17, pink to 10, red to 5, knives to 1. E.g 45(chance) >= x, output:blue is chosen, and from its list a random skin is selected."""
Output should be e.g: 8
I am using python 2.6. Unfortunately, I am unable to upgrade whatsoever.
Might be going out on a limb here, but maybe this will help
import random
cases = {
'wildfire' : ['1', '2', '3', '4', '5'],
'phoenix' : ['6', '7', '8', '9', '10'],
'gamma' : ['11', '12', '13', '14', '15'],
'chroma' : ['16', '17', '18', '19', '20'],
}
user_input = random.choice(cases.keys())
# user_input = one of 'wildfire', 'phoenix', 'gamma', or 'chroma'
index = random.randint(0, len(cases[user_input]))
# index = random integer between 0 and 4 used to index cases
chance = random.randint(1, 100)
for i, n in enumerate([35, 17, 5, 2]):
if chance >= n:
print "You've won a %s skin." % cases[user_input][index] + \
" With a chance of, %s" % chance
break
Sample outputs from running this snippet:
You've won a 15 skin. With a chance of, 84
You've won a 8 skin. With a chance of, 88
You've won a 20 skin. With a chance of, 76

Replacing values in a byte type NArray in Ruby

I am looking for a way to replace all occurrences of 'A' with 1, 'T' with 2, 'C' with 8, and 'G' with 16 in a byte array. How can this be done?
require "narray"
class NArray
def cast(type)
a = NArray.new(type,*self.shape)
a[] = self
a
end
end
conv = NArray.int(256)
atcg = NArray.to_na('ATCG', NArray::BYTE).cast(NArray::LINT)
conv[atcg] = [1,2,8,16]
seq_str = 'ABCDAGDE'
seq_ary = NArray.to_na(seq_str, NArray::BYTE).cast(NArray::LINT)
p conv[seq_ary]
#=> NArray.int(8):
# [ 1, 0, 8, 0, 1, 16, 0, 0 ]
Is it what you are looking for?
h = {'A' => 1, 'T' => 2, 'C' => 8, 'G' => 16}
a = ['A', 'B', 'C', 'D', 'A', 'G', 'D', 'E']
result = a.map {|c| h.include?(c) ? h[c] : c }

Parse abbreviated numbers in Ruby

What's the best way in Ruby to turn human-readable abbreviated numbers into actual integers?
Examples:
"1.2M" => 1200000
"477k" => 477000
module SIValue
# http://en.wikipedia.org/wiki/SI_prefix
PREFIX_MAGNITUDES = {
'Y' => 24, 'Z' => 21, 'E' => 18, 'P' => 15, 'T' => 12,
'G' => 9, 'M' => 6, 'k' => 3, 'h' => 2, 'da' => 1,
'd' => -1, 'c' => -2, 'm' => -3, 'μ' => -6, 'n' => -9,
'p' => -12, 'f' => -15, 'a' => -18, 'z' => -21, 'y' => -24
}
def self.from( str )
_, num, prefix = str.match(/^([-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)(#{PREFIX_MAGNITUDES.keys.join('|')})?/o).to_a
if num
prefix ? num.to_f * 10**PREFIX_MAGNITUDES[prefix] : num.to_f
else
0.0
end
end
end
%w[ 1k +3.3m +3.3M 123.123da 0.31h 0.31μ cats ].each do |s|
p [s,SIValue.from(s) ]
end
#=> ["1k", 1000.0]
#=> ["+3.3m", 0.0033]
#=> ["+3.3M", 3300000.0]
#=> ["123.123da", 1231.23]
#=> ["0.31h", 31.0]
#=> ["0.31μ", 3.1e-07]
#=> ["cats", 0.0]
def scale s
a = s.downcase.split /(?=[a-z])/
Integer(a.first.to_f * Hash.new(1).merge('k' => 1024, 'm' => 1024 * 1024)[a[1]] + 0.5)
end
# you may want to extend the hash with more suffix types

Resources