All possible permutations of a given String? - ruby

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)

Related

Is there a way to refactor this without using 3 collectors to combine strings?

I'm trying to refactor the following:
def method_name
array = ["abcdef", "ghijkl", "mnopqr"]
collector1 = ""
collector2 = ""
collector3 = ""
array.each do |string|
collector1 += string[0..1]
collector2 += string[2..3]
collector3 += string[4..5]
end
x = collector1 + "\n" + collector2 + "\n" + collector3
# "abghmn\ncdijop\nefklqr"
end
Are there any more efficient ways to write this? Or perhaps a different enumerable that will achieve the same result?
"abghmn\ncdijop\nefklqr" is the desired output!
Thanks!!
def method_name
array = ["abcdef", "ghijkl", "mnopqr"]
array.map { |s| s.chars.each_slice(2).to_a }.transpose.map(&:join).join("\n")
end
You could write the following.
array = ["abcdef", "ghijkl", "mnopqr"]
ranges = [0..1, 2..3, 4..5]
ranges.map { |r| array.map { |s| s[r] }.join }.join('\n')
#=> "abghmn\\ncdijop\\nefklqr"
or
ranges.map { |r| array.reduce('') { |t,s| t + s[r] } }.join('\n')
#=> "abghmn\\ncdijop\\nefklqr"

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))

String compressor (Ruby)

Here is my code in ruby for a word compression.
For any given word (e.g. abbbcca) the compressed word/output should be in the format as "letter+repetition" (for above example, output: a1b3c2a1).
Here I'm so close to the completion but my result isn't in the expected format. It's counting the whole letters in string.chars.each thus resulting output as a2b3c2a2.
Any help?
def string_compressor(string)
new_string = []
puts string.squeeze
string.squeeze.chars.each { |s|
count = 0
string.chars.each { |w|
if [s] == [w]
count += 1
end
}
new_string << "#{s}#{count}"
puts "#{new_string}"
}
if new_string.length > string.length
return string
elsif new_string.length < string.length
return new_string
else "Equal"
end
end
string_compressor("abbbcca")
'abbbcca'.chars.chunk{|c| c}.map{|c, a| [c, a.size]}.flatten.join
Adapted from a similar question.
Similar:
'abbbcca'.chars.chunk{|c| c}.map{|c, a| "#{c}#{a.size}"}.join
See chunk documentation
You can use a regular expression for that.
'abbbcca'.gsub(/(.)\1*/) { |m| "%s%d" % [m[0], m.size] }
#=> "a1b3c2a1"
The regular expression reads, "match any character, capturing it in group 1. Then match the contents of capture group 1 zero or more times".
As you said, your code counts every letter in the string, not just the one grouped next to one another.
Here's a modified version :
def display_count(count)
if count == 1
""
else
count.to_s
end
end
def string_compressor(string)
new_string = ''
last_char = nil
count = 0
string.chars.each do |char|
if char == last_char
count += 1
else
new_string << "#{last_char}#{display_count(count)}" if last_char
last_char = char
count = 1
end
end
new_string << "#{last_char}#{display_count(count)}" if last_char
new_string
end
p string_compressor('abbbcca') #=> "ab3c2a"
p string_compressor('aaaabbb') #=> "a4b3"
p string_compressor('aabb') #=> "a2b2"
p string_compressor('abc') #=> "abc"
Note that with display_count removing 1s from the string, new_string can never be longer than string. It also probably isn't a good idea to return Equal as a supposedly compressed string.
To decompress the string :
def string_decompressor(string)
string.gsub(/([a-z])(\d+)/i){$1*$2.to_i}
end
p string_decompressor("a5b11") #=> "aaaaabbbbbbbbbbb"
p string_decompressor("ab3c2a") #=> "abbbcca"

How to get words frequency in efficient way with ruby?

Sample input:
"I was 09809 home -- Yes! yes! You was"
and output:
{ 'yes' => 2, 'was' => 2, 'i' => 1, 'home' => 1, 'you' => 1 }
My code that does not work:
def get_words_f(myStr)
myStr=myStr.downcase.scan(/\w/).to_s;
h = Hash.new(0)
myStr.split.each do |w|
h[w] += 1
end
return h.to_a;
end
print get_words_f('I was 09809 home -- Yes! yes! You was');
This works but I am kinda new to Ruby too. There might be a better solution.
def count_words(string)
words = string.split(' ')
frequency = Hash.new(0)
words.each { |word| frequency[word.downcase] += 1 }
return frequency
end
Instead of .split(' '), you could also do .scan(/\w+/); however, .scan(/\w+/) would separate aren and t in "aren't", while .split(' ') won't.
Output of your example code:
print count_words('I was 09809 home -- Yes! yes! You was');
#{"i"=>1, "was"=>2, "09809"=>1, "home"=>1, "yes"=>2, "you"=>1}
def count_words(string)
string.scan(/\w+/).reduce(Hash.new(0)){|res,w| res[w.downcase]+=1;res}
end
Second variant:
def count_words(string)
string.scan(/\w+/).each_with_object(Hash.new(0)){|w,h| h[w.downcase]+=1}
end
def count_words(string)
Hash[
string.scan(/[a-zA-Z]+/)
.group_by{|word| word.downcase}
.map{|word, words|[word, words.size]}
]
end
puts count_words 'I was 09809 home -- Yes! yes! You was'
This code will ask you for input and then find the word frequency for you:
puts "enter some text man"
text = gets.chomp
words = text.split(" ")
frequencies = Hash.new(0)
words.each { |word| frequencies[word.downcase] += 1 }
frequencies = frequencies.sort_by {|a, b| b}
frequencies.reverse!
frequencies.each do |word, frequency|
puts word + " " + frequency.to_s
end
This works, and ignores the numbers:
def get_words(my_str)
my_str = my_str.scan(/\w+/)
h = Hash.new(0)
my_str.each do |s|
s = s.downcase
if s !~ /^[0-9]*\.?[0-9]+$/
h[s] += 1
end
end
return h
end
print get_words('I was there 1000 !')
puts '\n'
You can look at my code that splits the text into words. The basic code would look as follows:
sentence = "Ala ma kota za 5zł i 10$."
splitter = SRX::Polish::WordSplitter.new(sentence)
histogram = Hash.new(0)
splitter.each do |word,type|
histogram[word.downcase] += 1 if type == :word
end
p histogram
You should be careful if you wish to work with languages other than English, since in Ruby 1.9 the downcase won't work as you expected for letters such as 'Ł'.
class String
def frequency
self.scan(/[a-zA-Z]+/).each.with_object(Hash.new(0)) do |word, hash|
hash[word.downcase] += 1
end
end
end
puts "I was 09809 home -- Yes! yes! You was".frequency

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