Manipulating symbols in ruby - ruby

I am trying to take an array of symbols,
a = [:apple, :banana ,:grape, :black]
and add a string at the end of each symbol depending on the last letter. If the symbol ends with e, add "hello", otherwise "hi". I want to get:
[:applehello, :bananahi]
I did:
n = []
a.each do |b|
if (b[-1] == "e")
n.push b.to_s + "hello"
else
n.push b.to_s + "hi"
end
end
p n
I have to convert it into strings. How can I get the final output in symbols?
Did it using sub aswell-
a.each do |q|
if (q[-1]=="e")
then n.push q.to_s.sub(/e/,"ehello")
else
n.push q.to_s.sub(/\z/,"ahi")
end
end
p n

Use to_sym to have a symbol back
a = [:apple, :banana , :grape, :black]
a.map do |s|
(s.to_s + (s[-1] == 'e' ? 'hello' : 'hi')).to_sym
end
An alternative
a = [:apple, :banana , :grape, :black]
a.map do |s|
"#{s}#{s[-1] == 'e' ? 'hello' : 'hi'}".to_sym
end

Tried with following,
a.map { |x| "#{x}#{x.to_s.last == 'e' ? 'hello' : 'hi'}".to_sym }
# => [:applehello, :bananahi, :grapehello, :blackhi]

a.map{|sym| sym.to_s.sub(/.\z/) do
|c| case c; when "e" then "hello"; else "hi" end.to_sym
end}
# => [:applhello, :bananhi, :graphello, :blachi]

Related

How to swapcase a string without using builtin functions

I am trying to swapcase a string without using builtin functions like swapcase.
I came up with with the following code:
a = gets.split
b = ""
for i in a
if /[[:upper:]]/.match(i)
b += i.downcase
end
if /[[:lower:]]/.match(i)
b += i.upcase
end
end
puts b
But it's producing a wrong output. How can I do it in Ruby?
One approach to mimic swapcase with no argument.
p 'Hello'.chars.map { |c| c.upcase == c ? c.downcase : c.upcase }.join
#=> "hELLO"
"Hello World!".tr("a-zA-Z", "A-Za-z")
# => "hELLO wORLD!"
Similar to #sagarpandya82's answer but doesn't convert the string to an array and back.
"ComMMent maintEnaNt, vaChe tacHetée?".gsub(/./) do |c|
c == c.upcase ? c.downcase : c.upcase
end
#=> "cOMmmENT MAINTeNAnT, VAcHE TAChETÉE?"
def fnswapcase(a):
r = ' '
for i in a:
if ord(i) in range(97,123):
r+=chr(ord(i)-32)
elif ord(i) in range(65,91):
r+=chr(ord(i)+32)
else:
r+=i
return r
a=input("Enter a string:")
print(fnswapcase(a))

Finding the most occurring character/letter in a string

Trying to get the most occurring letter in a string.
So far:
puts "give me a string"
words = gets.chomp.split
counts = Hash.new(0)
words.each do |word|
counts[word] += 1
end
Does not run further than asking for a string. What am I doing wrong?
If you're running this in irb, then the computer may think that the ruby code you're typing in is the text to analyse:
irb(main):001:0> puts "give me a string"
give me a string
=> nil
irb(main):002:0> words = gets.chomp.split
counts = Hash.new(0)
words.each do |word|
counts[word] += 1
end=> ["counts", "=", "Hash.new(0)"]
irb(main):003:0> words.each do |word|
irb(main):004:1* counts[word] += 1
irb(main):005:1> end
NameError: undefined local variable or method `counts' for main:Object
from (irb):4:in `block in irb_binding'
from (irb):3:in `each'
from (irb):3
from /Users/agrimm/.rbenv/versions/2.2.1/bin/irb:11:in `<main>'
irb(main):006:0>
If you wrap it in a block of some sort, you won't get that confusion:
begin
puts "give me a string"
words = gets.chomp.split
counts = Hash.new(0)
words.each do |word|
counts[word] += 1
end
counts
end
gives
irb(main):001:0> begin
irb(main):002:1* puts "give me a string"
irb(main):003:1> words = gets.chomp.split
irb(main):004:1> counts = Hash.new(0)
irb(main):005:1> words.each do |word|
irb(main):006:2* counts[word] += 1
irb(main):007:2> end
irb(main):008:1> counts
irb(main):009:1> end
give me a string
foo bar
=> {"foo"=>1, "bar"=>1}
Then you can work on the fact that split by itself isn't what you want. :)
This should work:
puts "give me a string"
result = gets.chomp.split(//).reduce(Hash.new(0)) { |h, v| h.store(v, h[v] + 1); h }.max_by{|k,v| v}
puts result.to_s
Output:
#Alan ➜ test rvm:(ruby-2.2#europa) ruby test.rb
give me a string
aa bbb cccc ddddd
["d", 5]
Or in irb:
:008 > 'This is some random string'.split(//).reduce(Hash.new(0)) { |h, v| h.store(v, h[v] + 1); h }.max_by{|k,v| v}
=> ["s", 4]
Rather than getting a count word by word, you can process the whole string immediately.
str = gets.chomp
hash = Hash.new(0)
str.each_char do |c|
hash[c] += 1 unless c == " " #used to filter the space
end
After getting the number of letters, you can then find the letter with highest count with
max = hash.values.max
Then match it to the key in the hash and you're done :)
puts hash.select{ |key| hash[key] == max }
Or to simplify the above methods
hash.max_by{ |key,value| value }
The compact form of this is :
hash = Hash.new(0)
gets.chomp.each_char { |c| hash[c] += 1 unless c == " " }
puts hash.max_by{ |key,value| value }
This returns the highest occurring character within a given string:
puts "give me a string"
characters = gets.chomp.split("").reject { |c| c == " " }
counts = Hash.new(0)
characters.each { |character| counts[character] += 1 }
print counts.max_by { |k, v| v }

All possible permutations of a given String?

How would I do this in Ruby?
p "abc".all_possible_permutations
Would return:
[
"abc",
"acb",
"bca",
"bac",
"cba",
"cab",
]
Edit
Thanks to Jakub Hampl:
class String
def all_possible_permutations
self.chars.to_a.permutation.map(&:join)
end
end
%w[a b c].permutation.map &:join
If someone doesnt want to use inbuilt function :
def permute(result,input)
if(input.length == 0)
return
end
if(input.length == 1)
puts result + input[0]
return
end
if(input.length == 2)
puts result + input[0] + input[1]
puts result + input[1] + input[0]
return
end
(0...input.length).step(1).each do |i|
firstpart = result+input[i]
secondpart = (i > 0 ? input[0..(i-1)] : '') + (input[(i+1)..-1] || '')
permute(firstpart,secondpart)
end
end
permute('',gets.chomp)
One line:
p "abc".chars.permutation.map &:join
Sample output:
["abc", "acb", "bac", "bca", "cab", "cba"]
p is optional
string could be a variable instead
chars is pretty quick, it separates the string into an array of single characters
map has tons of cool applications,it takes a object, and returns it after the block is done, in this case the operation join
&:join could be replaced with { |i| i.join } like this:
p "abc".chars.permutation.map{ |i| i.join }
If anyone wants to have the code for this using basic algorithms, here is how you do it-
$count = 0
def permute(permuted_string, original_string, done_array)
if permuted_string.length == original_string.length
$count = $count+1
puts "#{$count} #{permuted_string}"
else
(0..original_string.length-1).each do |i|
if !done_array[i]
done_array[i] = true
permute(permuted_string+original_string[i], original_string, done_array)
done_array[i] = false
end
end
end
end
puts "Please enter the string for permutations"
input = gets.chomp
done_array = Array.new(input.length, false)
permute("", input, done_array)

assigning mapped array directly

Trying to map stuff I read from a file into a
list of arrays that have an integer and a string
It doesn't seem to to work quite right, because I see
two strings per array, as opposed to an integer
and a string.
list_of_elems = []
File.foreach("line_counts.txt") do |line|
list_of_elems << arr = line.split(/\s+/).map! { |e, i| i == 0 ? e.to_i : e }
end
list_of_elems.each_with_index do |e, i|
if i > 10
break
end
p e
end
If I understand well, you want to take a file like this:
test 20 foo
7 1 bar 6
And get this:
[["test", 20, "foo"],
[7, 1, "bar", 6]]
Right?
Then you can use:
list_of_elems = []
File.foreach("line_counts.txt") do |line|
list_of_elems << line.split(/\s+/).map {|e| e =~ /^(?:+|-)?\d+$/ ? e.to_i : e }
end
Or:
list_of_elems = File.read("line_counts.txt").split("\n").map do |line|
line.split(/\s+/).map {|e| e =~ /^(?:+|-)?\d+$/ ? e.to_i : e }
end
This may not be too relevant, but
list_of_elems.each_with_index do |e, i|
if i > 10
break
end
p e
end
can be replaced with
list_of_elems[0..10].each {|e| p e}
Your problem is that map! only passes one argument to the block; hence i is always nil, i == 0 always fails, and to_i is never called. I think you want something more like this:
list_of_items = File.open('line_counts.txt').collect do |line|
line.split(/\s+/).inject([ ]) { |a, e| a.push(a.length == 0 ? e.to_i : e) }
end
The a.length == 0 essentially replaces your faulty i == 0 check and converts the first component of the line to an integer.
If linecounts.txt looks like this:
1 one
2 two
Then list_of_items ends up looking like this:
[[1, "one"], [2, "two"]]
and that seems to be what you're after.
This should work too:
list_of_elems = File.foreach("line_counts.txt").map |line|
line.split.map.with_index { |e, i| i == 0 ? e.to_i : e }
end
I use map instead of each for the output because you can hit tab twice in textmate and it builds the block for you.
list_of_elems.map { |e| puts e.to_s }

comparing multiple strings character by character and outputting the overlap?

ruby
i have the following
p = 0
[s1.size,s2.size].max.times { |c| if s1[c] == s2[c]; p = c; else break; end };
matched_part = s1[0..p]
but i dont know how i can this for multiple strings (more than 2) at the same time.
Alright, how's this?
class String
def self.overlap(s1,s2,*strings)
strings += [s2]
strings.min { |s| s.size }.size.times do |n|
return s1[0,n] unless strings.all? { |string| s1[n]==string[n] }
end
s1
end
end
class String
def self.overlap(first,second,*others)
s1 = first
others = [second] + others
others.each do |s2|
p = 0
s1.length.times { |c| if s1[c] == s2[c] then p = c else break end }
s1 = s1[0..p]
end
s1
end
end
puts String.overlap "marry had a little lamb", "marry had a bug dog", "marry had a cat", "marry had a bird OUT:", "marry had something" #=> marry had
In one line:
strings[0].slice(0,(0...strings[0].size).find {|i| strings.map {|s| s[i..i]}.uniq.size > 1})

Resources