Writting a method to check the number of vowels in a string - ruby-on-rails

I have a hash of data that is holding different strings as its Key. I need to create a new method in my class that will count the number of vowels in each key and then return the key with the most vowels. I am very stuck and this is what I have so far.
def favorite_wish
vowels = ["a", "e", "i", "o", "u"]
#submitted_wishes.each_key do |wish|
wish.split(' ')
wish.each do |check|
if check == vowels
end
end
end
Can anyone help?

String#count might help you:
# this will return the key with the max number of vowels
def favorite_wish
#submitted_wishes.keys.max_by { |wish| wish.count('aeiou') }
end
# this will return the value to the key with the max number of vowels
def favorite_wish
max_key = #submitted_wishes.keys.max_by { |wish| wish.count('aeiou') }
#submitted_wishes[max_key]
end

This will get the key with the most vowels:
#submitted_wishes.keys.max_by { |key| key.count('aeiou') }

I would use the following methods:
def count_vowels(str)
str.count 'aeiou'
end
def highest_value_key(hash)
hash.key(hash.values.max)
end
The idea behind these methods is to separate concerns and make it more readable.

h = { "Mary"=>"Mary", "quite"=>"contrary", "how"=>"does your", "garden"=>"grow?" }
h.map { |k,_| [k.count('aeiou'), k] }.max.last
#=> => "quite"
The steps:
a = h.map { |k,_| [k.count('aeiou'), k] }
#=> [[1, "Mary"], [3, "quite"], [1, "how"], [2, "garden"]]
b = a.max
#=> [3, "quite"]
b.last
#=> "quite"
See Array#<=> for an explanation of how arrays are ordered (when computing max).
If keys k1 and k2 tie for the maximum number of vowels, k1 <=> k2 breaks the tie (k1 is returned if k1 <=> k2 #=> -1, k2 is returned if k1 <=> k2 #=> 1, either key might be returned if k1 <=> k2 #=> 0. See String#<=>.

Related

How do I split a string given an array of split positions?

I'm using Ruby 2.4 and Rails 5. I have an array of indexes within a line
[5, 8, 10]
How do I take the above array, and a string, and form anotehr array of strings that are split by the above indexes? FOr instance, if the string is
abcdefghijklmn
and split it based ont eh above indexes, I would have an array with the following strings
abcde
fgh
ij
klmn
Try this
str = "abcdefghijklmn"
positions = [5, 8, 10]
parts = [0, *positions, str.size].each_cons(2).map { |a, b| str[a...b] }
# => ["abcde", "fgh", "ij", "klmn"]
Or,
If the positions are constant and known ahead of runtime (for example if they were the format for a phone number or credit card) just use a regexp
str.match(/(.....)(...)(..)(.*)/).captures
# => ["abcde", "fgh", "ij", "klmn"]
This will get the Job done
str = "abcdefghijklmn"
arr_1 = [5, 8, 10]
arr_2, prev = [], 0
(arr_1.length + 1).times do |x|
if arr_1[x] == nil then arr_1[x] = str.size end
arr_2 << str[prev..arr_1[x] -1]
prev = arr_1[x]
end
p arr_2
---------------------------------------
Program Run Output
["abcde", "fgh", "ij", "klmn"]
---------------------------------------
I hope this Helps

How to not allowed taking in a number into a variable in Ruby

Given a string S of length N that is indexed from 0 to N-1 , print its even-indexed and odd-indexed characters as space-separated strings on a single line (see the Sample below for more detail).
Sample Input:
2
Hacker
Rank
Sample output:
Hce akr
Rn ak
explanation:
S="Hacker" S[0]="H", S[1]="a", S[2]= "c", S[3]="k", S[4]="e", S[5]="r"
However, with the following code I haven't been able to complete the challenge. How do I constraint taken input as an integer?
S = gets.chomp.chars.to_a
for i in 0..S.length
if i%2 == 0
s1 = S[i]
else
s2 = S[i]
end
end
puts s1.to_s + " " + s2.to_s
Code
def doit(str)
str.each_char.each_slice(2).with_object(['','']) do |(c_even, c_odd), (s_even, s_odd)|
s_even << c_even
s_odd << c_odd unless c_odd.nil?
end.join(' ')
end
Examples
doit "abracadabra"
#=> "arcdba baaar"
doit "Jack be nimble, Jack be quick"
#=> "Jc enml,Jc eqik akb ibe akb uc"
Explanation
For
str = "abracadabra"
enum0 = str.each_char
#=> #<Enumerator: "abracadabra":each_char>
We can convert the enumerator enum0 to an array to see what values it will generate:
enum0.to_a
#=> ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
enum1 = enum0.each_slice(2)
#=> #<Enumerator: #<Enumerator: "abracadabra":each_char>:each_slice(2)>
enum1.to_a
#=> [["a", "b"], ["r", "a"], ["c", "a"], ["d", "a"], ["b", "r"], ["a"]]
enum2 = enum1.with_object(['',''])
#=> #<Enumerator: #<Enumerator: #<Enumerator: "abracadabra":each_char>:each_slice(2)>
# :with_object(["", ""])>
enum2.to_a
#=> [[["a", "b"], ["", ""]], [["r", "a"], ["", ""]], [["c", "a"], ["", ""]],
# [["d", "a"], ["", ""]], [["b", "r"], ["", ""]], [["a"], ["", ""]]]
If you examine the return values obtained when constructing enum1 and enum2, you will see that they can be thought of as "compound" enunerators.
The first element of enum2 is generated and passed to the block, assigning values to the four block variables1:
(c_even, c_odd), (s_even, s_odd) = enum2.next
#=> [["a", "b"], ["", ""]]
c_even #=> "a"
c_odd #=> "b"
s_even #=> ""
s_odd #=> ""
The block calculation is now performed.
s_even << c_even
#=> "a"
s_odd << c_odd unless c_odd.nil?
# s_odd << c_odd unless false
# s_odd << c_odd
#=> "b"
The return values "a" and "b" are the new values of s_even and s_odd, respectively.
Now the next element of enum_2 is generated, passed to the block and the block calculations are performed:
(c_even, c_odd), (s_even, s_odd) = enum2.next
#=> [["r", "a"], ["a", "b"]]
s_even << c_even
# "a" << "r"
#=> "ar"
s_odd << c_odd unless c_odd.nil?
# s_odd << c_odd unless "a".nil?
# s_odd << c_odd
#=> "ba"
Calculations continue in this way until the last value of enum2 is generated: ["a"]. This has the effect of assigning nil to c_odd, so the second line of the block is not executed2. Lastly, the array of two strings is joined with a separating space.
Another way
def doit(str)
str.each_char.with_index.with_object(' ') { |(c,i),s|
s.insert(i.even? ? s.index(' ') : s.size, c) }
end
doit "abracadabra"
#=> "arcdba baaar"
1 The following expression employs parallel assignment (sometimes called multiple assignment) and disambiguation (sometimes referred to as decomposition) to assign values to the variables.
2 The second line could alternatively be written s_odd << c_odd.to_s or s_odd << c_odd || ''.
First input should be treated as an integer (namely, the amount of following strings to come):
amount = gets.to_i
Now we are to get amount strings and do our job (using Enumerable#partition):
amount.times do
input = gets.chomp
puts (input.split('').partition.with_index do |_, i|
i.even?
end.map(&:join).join(' '))
end
Note that instead of inspecting each character's index, you could also use scan:
'Hacker'.scan(/(.)(.?)/) #=> [["H", "a"], ["c", "k"], ["e", "r"]]
.transpose #=> [["H", "c", "e"], ["a", "k", "r"]]
.map(&:join) #=> ["Hce", "akr"]
.join(' ') #=> "Hce akr"
Or, using temporary variables:
s1 = ''
s2 = ''
'Hacker'.scan(/(.)(.?)/) { |a, b| s1 << a ; s2 << b }
puts "#{s1} #{s2}"
Here is the basic algorithm that would take O(n).
tests = gets.to_i
# run the loop for number of tests given
tests.times do
string = gets.chomp # sanitize string from input, i.e. removes \n \r
s_length = string.length # String length N
new_string = " " * s_length # create of string of length N
even_index = 0 # because evens are going to come first
odd_index = s_length - (s_length/2) + 1 # odds are going to start where even numbers end + 1
0.upto(s_length-1) do |i|
if i%2 == 0
new_string[even_index] = string[i]
even_index += 1
elsif
new_string[odd_index] = string[i]
odd_index += 1
end
end
puts new_string
end
Benchmark:
require 'benchmark'
def using_ugly_algo(tests, string)
# tests = gets.to_i
tests.times do
string = string
s_length = string.length # String length N
new_string = " " * s_length # creat of string of length N
even_index = 0
odd_index = s_length - (s_length/2) + 1
0.upto(s_length-1) do |i|
if i%2 == 0
new_string[even_index] = string[i]
even_index += 1
elsif
new_string[odd_index] = string[i]
odd_index += 1
end
end
# new_string
end
end
def with_partition(amount, string)
amount.times do
input = string
(input.split('').partition.with_index do |_, i|
i.even?
end.map(&:join).join(' '))
end
end
n = 10_000
string = (0...500).map { ('a'..'z').to_a[rand(26)] }.join
Benchmark.bmbm(100) do |x|
x.report("using_ugly_algo "){ n.times { using_ugly_algo(5, string) } }
x.report("with_partition "){ n.times { with_partition(5, string) } }
end
Report:
Rehearsal ----------------------------------------------------------------------------------------------------------------------------------------
using_ugly_algo 13.790000 0.030000 13.820000 ( 13.843560)
with_partition 16.790000 0.030000 16.820000 ( 16.830992)
------------------------------------------------------------------------------------------------------------------------------ total: 30.640000sec
user system total real
using_ugly_algo 13.930000 0.060000 13.990000 ( 14.070378)
with_partition 18.640000 0.210000 18.850000 ( 19.392816)
Well, the problem you are having is, if I am using the right term, a usage error. Your code is setting s1 and s2 to whatever the last checked letter is instead of concatenating. Modifying you code, I suppose what you are looking for is something like this:
S = gets.chomp.chars.to_a
s1 = ""
s2 = ""
for i in 0...S.length
if i%2 == 0
s1.concat(S[i])
else
s2.concat(S[i])
end
end
puts s1.to_s + " " + s2.to_s

ruby arrays count of most frequent element [duplicate]

This question already has answers here:
How to find an item in array which has the most occurrences [duplicate]
(11 answers)
Closed 6 years ago.
I'm trying to figure out how to find a count of the most frequent element in an array of integers. I can think of a few methods that might be helpful but when I get to writing an expression inside the block I get complete lost on how to compare an element with the next and previous element. Any ideas? All help is really really appreciated!!!
An easy was is to determine all the unique values, convert each to its count in the array, then determine the largest count.
def max_count(arr)
arr.uniq.map { |n| arr.count(n) }.max
end
For example:
arr = [1,2,4,3,2,6,3,4,2]
max_count(arr)
#=> 3
There are three steps:
a = arr.uniq
#=> [1, 2, 4, 3, 6]
b = a.map { |n| arr.count(n) }
#=> [1, 3, 2, 2, 1]
b.max
#=> 3
A somewhat more efficient way (because the elements of arr are enumerated only once) is to use a counting hash:
def max_count(arr)
arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }.values.max
end
max_count(arr)
#=> 3
We have:
a = arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }
#=> {1=>1, 2=>3, 4=>2, 3=>2, 6=>1}
b = a.values
#=> [1, 3, 2, 2, 1]
b.max
#=> 3
See Hash::new for an explanation of Hash.new(0). Briefly, if h = Hash.new(0) and h does not have a key k, h[k] will return the default value, which here is zero. h[k] += 1 expands to h[k] = h[k] + 1, so if h does not have a key k, this becomes h[k] = 0 + 1. On the other hand, if, say, h[k] => 2, then h[k] = h[k] + 1 #=> h[k] = 3 + 1.

Creating a range from one column

I have a column called "Marks" which contains values like
Marks = [100,200,150,157,....]
I need to assign Grades to those marks using the following key
<25=0, <75=1, <125=2, <250=3, <500=4, >500=5
If Marks < 25, then Grade = 0, if marks < 75 then grade = 1.
I can sort the results and find the first record that matches using Ruby's find function. Is it the best method ? Or is there a way by which I can prepare a range using the key by adding Lower Limit and Upper Limit columns to the table and by populating those ranges using the key? Marks can have decimals too Ex: 99.99
Without using Rails, you could do it like this:
marks = [100, 200, 150, 157, 692, 12]
marks_to_grade = { 25=>0, 75=>1, 125=>2, 250=>3, 500=>4, Float::INFINITY=>5 }
Hash[marks.map { |m| [m, marks_to_grade.find { |k,_| m <= k }.last] }]
#=> {100=>2, 200=>3, 150=>3, 157=>3, 692=>5, 12=>0}
With Ruby 2.1, you could write this:
marks.map { |m| [m, marks_to_grade.find { |k,_| m <= k }.last] }.to_h
Here's what's happening:
Enumerable#map (a.k.a collect) converts each mark m to an array [m, g], where g is the grade computed for that mark. For example, when map passes the first element of marks into its block, we have:
m = 100
a = marks_to_grade.find { |k,_| m <= k }
#=> marks_to_grade.find { |k,_| 100 <= k }
#=> [125, 2]
a.last
#=> 2
so the mark 100 is mapped to [100, 2]. (I've replaced the block variable for the value of the key-value pair with the placeholder _ to draw attention to the fact that the value is not being used in the calculation within the block. One could also use, say, _v as the placeholder.) The remaining marks are similarly mapped, resulting in:
b = marks.map { |m| [m, marks_to_grade.find { |k,_| m <= k }.last] }
#=> [[100, 2], [200, 3], [150, 3], [157, 3], [692, 5], [12, 0]]
Lastly
Hash[b]
#=> {100=>2, 200=>3, 150=>3, 157=>3, 692=>5, 12=>0}
or, for Ruby 2.1+
b.to_h
#=> {100=>2, 200=>3, 150=>3, 157=>3, 692=>5, 12=>0}
You can make use of update_all:
Student.where(:mark => 0...25).update_all(grade: 0)
Student.where(:mark => 25...75).update_all(grade: 1)
Student.where(:mark => 75...125).update_all(grade: 2)
Student.where(:mark => 125...250).update_all(grade: 3)
Student.where(:mark => 250...500).update_all(grade: 4)
Student.where("mark > ?", 500).update_all(grade: 5)

How to determine if one array contains all elements of another array

Given:
a1 = [5, 1, 6, 14, 2, 8]
I would like to determine if it contains all elements of:
a2 = [2, 6, 15]
In this case the result is false.
Are there any built-in Ruby/Rails methods to identify such array inclusion?
One way to implement this is:
a2.index{ |x| !a1.include?(x) }.nil?
Is there a better, more readable, way?
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]
a - b
# => [5, 1, 14, 8]
b - a
# => [15]
(b - a).empty?
# => false
Perhaps this is easier to read:
a2.all? { |e| a1.include?(e) }
You can also use array intersection:
(a1 & a2).size == a1.size
Note that size is used here just for speed, you can also do (slower):
(a1 & a2) == a1
But I guess the first is more readable. These 3 are plain ruby (not rails).
This can be achieved by doing
(a2 & a1) == a2
This creates the intersection of both arrays, returning all elements from a2 which are also in a1. If the result is the same as a2, you can be sure you have all elements included in a1.
This approach only works if all elements in a2 are different from each other in the first place. If there are doubles, this approach fails. The one from Tempos still works then, so I wholeheartedly recommend his approach (also it's probably faster).
If there are are no duplicate elements or you don't care about them, then you can use the Set class:
a1 = Set.new [5, 1, 6, 14, 2, 8]
a2 = Set.new [2, 6, 15]
a1.subset?(a2)
=> false
Behind the scenes this uses
all? { |o| set.include?(o) }
You can monkey-patch the Array class:
class Array
def contains_all?(ary)
ary.uniq.all? { |x| count(x) >= ary.count(x) }
end
end
test
irb(main):131:0> %w[a b c c].contains_all? %w[a b c]
=> true
irb(main):132:0> %w[a b c c].contains_all? %w[a b c c]
=> true
irb(main):133:0> %w[a b c c].contains_all? %w[a b c c c]
=> false
irb(main):134:0> %w[a b c c].contains_all? %w[a]
=> true
irb(main):135:0> %w[a b c c].contains_all? %w[x]
=> false
irb(main):136:0> %w[a b c c].contains_all? %w[]
=> true
irb(main):137:0> %w[a b c d].contains_all? %w[d c h]
=> false
irb(main):138:0> %w[a b c d].contains_all? %w[d b c]
=> true
Of course the method can be written as a standard-alone method, eg
def contains_all?(a,b)
b.uniq.all? { |x| a.count(x) >= b.count(x) }
end
and you can invoke it like
contains_all?(%w[a b c c], %w[c c c])
Indeed, after profiling, the following version is much faster, and the code is shorter.
def contains_all?(a,b)
b.all? { |x| a.count(x) >= b.count(x) }
end
Most answers based on (a1 - a2) or (a1 & a2) would not work if there are duplicate elements in either array. I arrived here looking for a way to see if all letters of a word (split to an array) were part of a set of letters (for scrabble for example). None of these answers worked, but this one does:
def contains_all?(a1, a2)
try = a1.chars.all? do |letter|
a1.count(letter) <= a2.count(letter)
end
return try
end
Depending on how big your arrays are you might consider an efficient algorithm O(n log n)
def equal_a(a1, a2)
a1sorted = a1.sort
a2sorted = a2.sort
return false if a1.length != a2.length
0.upto(a1.length - 1) do
|i| return false if a1sorted[i] != a2sorted[i]
end
end
Sorting costs O(n log n) and checking each pair costs O(n) thus this algorithm is O(n log n). The other algorithms cannot be faster (asymptotically) using unsorted arrays.
I was directed to this post when trying to find whether one array ["a", "b", "c"] contained another array ["a", "b"], where in my case identical ordering was an additional requirement to the question.
Here is my solution (I believe it's O(n) complexity), to anyone who has that extra requirement:
def array_includes_array(array_to_inspect, array_to_search_for)
inspectLength = array_to_inspect.length
searchLength = array_to_search_for.length
if searchLength == 0 then
return true
end
if searchLength > inspectLength then
return false
end
buffer = []
for i in 0..inspectLength
buffer.push(array_to_inspect[i])
bufferLastIndex = buffer.length - 1
if(buffer[bufferLastIndex] != array_to_search_for[bufferLastIndex]) then
buffer.clear
next
end
if(buffer.length == searchLength) then
return true
end
end
return false
end
This produces the test results:
puts "1: #{array_includes_array(["a", "b", "c"], ["b", "c"])}" # true
puts "2: #{array_includes_array(["a", "b", "c"], ["a", "b"])}" # true
puts "3: #{array_includes_array(["a", "b", "c"], ["b", "b"])}" # false
puts "4: #{array_includes_array(["a", "b", "c"], ["c", "b", "a"])}" # false
puts "5: #{array_includes_array(["a", "b", "c"], [])}" # true
puts "6: #{array_includes_array([], ["a"])}" # false
puts "7: #{array_includes_array([], [])}" # true

Resources