How to search for the longest word in the string - ruby

def my_inject(*args)
return yield false if args.empty? && !block_given?
case args.length
when 1 then args.first.is_a?(Symbol) ? sym = args.first : result = args.first
when 2 then result = args.first
sym = args.last
end
result ||= 0
my_each { |x| result = block_given? ? yield(result, x) : result.send(sym, x) }
result
end
What can I add to this code to make it search for the longest word in Array of strings and were add it?

string.split(" ")
.max_by(&:length)
See Enumerable#max_by.

What can I add to this code to make it search for the longest word in a string
"this is a test of the emergency broadcast system".split(' ').sort {|x,y| y.length <=> x.length}.first
To break this down we:
assign a sentence as a string
split that string into words
sort each word by comparing its length with the previous word's length
take the first result
More information on sorting in Ruby at https://apidock.com/ruby/v2_5_5/Enumerable/sort

Some assumptions:
Each array item only contains one word
You only want the longest word returned, not the position
words = %w[tiny humungous antidisestablishmentarianism medium]
puts words.max_by(&:length)

Related

Ruby - Remove 1 or 2 character from a string to make it a palindrome

I had a technical test for an entry-level job 2 days ago. It went well apart from the last assessment.
I will go over the assessment with the CTO tomorrow and was hoping I could get help to get my head around this one, so I do not sound clueless.
It was something like this:
Given string as an argument, give us palindrome method that would check if a palindrome of a minimum 3 characters can be created by removing 1 or 2 characters. The string has no special characters, numbers or whitespace basically only letters (eg: str = "abecbea")
If true, print letters removed, if false print "not possible"
"remove 1 or 2 characters" and "print letters removed" is giving me a headache legit
I have tried a lot of different things but for the last 2 days but i am completely stuck!
[EDIT]
Ideas i started with below
def is_palindrome(s)
s == s.reverse && s.length >= 3
end
def possible_palin_by_removing_one_char(s)
array_chars = s.chars
first_char = array_chars[0]
last_char = array_chars[-1]
while first_char < last_char
if first_char != last_char
first_char += 1
last_char -= 1
else
if is_palindrome
puts ????
else
puts "not possible"
end
end
end
end
or
def palindrome?(string)
deleted_chars = []
candidates = 0.upto(string.length-1).map do |index|
array_chars = string.chars
deleted_chars << array_chars.delete_at(index)
array_chars
end
if candidates.any? { |c| c.reverse == c } && string.length >= 3
puts "It is a palindrome with letters '#{deleted_chars.join(",")}' removed !"
# puts deleted_chars
else
if string.length <= 3
puts "String '#{string}' is too short"
else
puts "This is not possible to create palindrome with string '#{string}'"
end
end
end
palindrome?("abcecbae")
I would love someone to help me solve this one
Thanks heaps for your help
Put all chars in an Array (ar = str.chars)
Try all combinations which are 2 less than
the size of the array (so 5 in the example "abcecbae")(ar.combination(5))
Select all combinations which happen to be equal to their reverse
Map the result(s) back from arrays to strings
Similar for 1 removed char.
This task might be a little bit trickier without Ruby's rich standard library support.
Here is how I'd solve this task in the 1st iteration:
Check if the original string is a palindrome, return immediately if it is
Build a list of possible combinations of indices to remove
Iterate over this list, check if removing the chars at given indices makes our input string a palindrome
The trickiest part here is (2), but Enumerable#permutation almost does the job.
So, something like
def palindrome?(s)
s == s.reverse
end
def indices_to_remove(string)
ary = (0..string.size-1).to_a
# Permutations like [0,1] and [1,0] means the same in our context, so we need to remove this duplication.
(ary.map { |x| [x] } + ary.permutation(2).map(&:sort)).uniq
end
def remove_chars(str, *indices)
str.dup.tap do |s|
indices.sort.reverse_each { |i| s[i] = '' }
end
end
def find_palindrome(str)
return if palindrome?(str)
indices_to_remove(str).each do |indices|
new_str = remove_chars(str, *indices)
return "Letters removed: #{indices.inspect}; palindrome: '#{new_str}'" if palindrome?(new_str)
end
end
That's it. Let's see if i works:
pry(main)> find_palindrome("abecbea")
=> "Letters removed: [1, 3]; palindrome: 'aebea'"
It does. Adjust the filtering logic (check palindroms' size as needed) and output if necessary.
Thanks all for your help. With the help of a senior dev, we came up with the below solution
def palindrome_check(str)
length = str.length
# convert to array of chars
chars = str.chars
# check if palindrome by deleting 1 characters
length.times do |i|
char = chars.delete_at(i)
return "Letter '#{char}' has been removed from String '#{str}' to create palindrome" if chars == chars.reverse
# return the array to original condition
chars.insert(i, char)
end
# only do remove 2 characters check if length > 4, as otherwise removing would result in a string less than 3 characters
if length > 4
length.times do |i|
length.times do |j|
# avoid repeating the same checks
next if j <= i
# since j is always greater than i, remove j first to avoid affecting which character is at position i
char_two = chars.delete_at(j)
char_one = chars.delete_at(i)
return "Letters '#{[char_one, char_two].join(' and ')}' has been removed from String '#{str}' to create palindrome" if chars == chars.reverse
# return the array to original condition
chars.insert(i, char_one)
chars.insert(j, char_two)
end
end
end
return "'#{str}' can't be a Palindrome"
end
palindrome_check('string') # 'can't be a Palindrome'
palindrome_check('abcdcfba') # 'f'
palindrome_check('rqubyxyburx') # 'q, x'

calling the method 'count' returns wrong number of arguments

I have a method which takes two parameters. An integer for (max_length) and a string for (text). If the amount of characters per word in the text is >= max_length we remove that word from the array. At the end we count the remaining words in the array.
My method works well until text.count where I encounter 'wrong number of arguments, given 0 expected 1+'
I know this is because we haven't passed any arguments to text.count but I don't want to pass any in as I only want to count the remaining number of words left in the array.
However, if I performed a simple example of
x = ["This", "Will", "Work"]
x.count => 3
Why can't I use this example of count inside my block?
What am i doing wrong?
def timed_reading(max_length, text)
text.split.delete_if do |y|
y.length >= max_length
text.count
end
end
I think this is what you were trying to do
def timed_reading(max_length, text)
text.split.delete_if { |y| y.length >= max_length }.count
end
You could just count words with length less than the max anyway
text.split.count { |y| y.length < max_length }
There's no need to delete words if all you return is the count. You can simply use count with a block:
def timed_reading(max_length, text)
text.split.count{|w| w.length < max_length}
end
You are calling count on the string text and not on the array. You need to rearrange your code so that you are calling count on the result of your delete_if call. Something like this:
def timed_reading(max_length, text)
short_words = text.split.delete_if do |y|
y.length >= max_length
end
short_words.count
end

Can't get Ruby method to pass spec for Anagram method

I'm trying to get this to pass spec to verify if an argument is an anagram of another word, but it's just not happening.
I can get the string (starting with just one sting word) into an array, and whether it's one or multiple words,
It then iterates through the array over each word.
Using the If statement to compare if the sorted object is equal to the sorted argument.
Applied .join, since it came out one letter at a time in irb, but it's still not happening, with or without .join.
class String
define_method(:anagrams) do |check_word|
words = self.downcase
check_word = check_word.downcase
words_array = words.split(" ")
words_array.each do |word|
if (word.chars.sort) == (check_word.chars.sort)
true
else
false
end
end
end
end
Any ideas why it's broken?
words_array.each do |word|
if (word.chars.sort) == (check_word.chars.sort)
true
else
false
end
end
I'm assuming you want to return true if any words are anagrams. You're currently not explicitly returning.
Better Ruby syntax would be words_array.any? { |word| word.chars.sort == check_word.chars.sort) }
OR
words_array.each do |word|
return true if (word.chars.sort) == (check_word.chars.sort)
end
Here's another way to see if two words w1 and w2 are anagrams of each other:
def anagrams?(w1, w2)
w1.size == w2.size && w1.chars.difference(w2.chars).empty?
end
where Array#difference is how I defined it in my answer here.
Array#difference is similar to Array#-. The difference is illustrated in the following example:
a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]
a - b #=> [1]
a.difference b #=> [1, 3, 2, 2]
Let's try it:
anagrams?("tops", "stop") #=> true
anagrams?("tops", "stopz") #=> false
anagrams?("tops", "stopz") #=> false
anagrams?("tops", "sto") #=> false

Find if all letters in a string are unique

I need to know if all letters in a string are unique. For a string to be unique, a letter can only appear once. If all letters in a string are distinct, the string is unique. If one letter appears multiple times, the string is not unique.
"Cwm fjord veg balks nth pyx quiz."
# => All 26 letters are used only once. This is unique
"This is a string"
# => Not unique, i and s are used more than once
"two"
# => unique, each letter is shown only once
I tried writing a function that determines whether or not a string is unique.
def unique_characters(string)
for i in ('a'..'z')
if string.count(i) > 1
puts "This string is unique"
else
puts "This string is not unique"
end
end
unique_characters("String")
I receive the output
"This string is unique" 26 times.
Edit:
I would like to humbly apologize for including an incorrect example in my OP. I did some research, trying to find pangrams, and assumed that they would only contain 26 letters. I would also like to thank you guys for pointing out my error. After that, I went on wikipedia to find a perfect pangram (I wrongly thought the others were perfect).
Here is the link for reference purposes
http://en.wikipedia.org/wiki/List_of_pangrams#Perfect_pangrams_in_English_.2826_letters.29
Once again, my apologies.
s = "The quick brown fox jumps over the lazy dog."
.downcase
("a".."z").all?{|c| s.count(c) <= 1}
# => false
Another way to do it is:
s = "The quick brown fox jumps over the lazy dog."
(s.downcase !~ /([a-z]).*\1/)
# => false
I would solve this in two steps: 1) extract the letters 2) check if there are duplicates:
letters = string.scan(/[a-z]/i) # append .downcase to ignore case
letters.length == letters.uniq.length
Here is a method that does not convert the string to an array:
def dupless?(str)
str.downcase.each_char.with_object('') { |c,s|
c =~ /[a-z]/ && s.include?(c) ? (return false) : s << c }
true
end
dupless?("Cwm fjord veg balks nth pyx quiz.") #=> true
dupless?("This is a string.") #=> false
dupless?("two") #=> true
dupless?("Two tubs") #=> false
If you want to actually keep track of the duplicate characters:
def is_unique?(string)
# Remove whitespaces
string = string.gsub(/\s+/, "")
# Build a hash counting all occurences of each characters
h = Hash.new { |hash, key| hash[key] = 0 }
string.chars.each { |c| h[c] += 1 }
# An array containing all the repetitions
res = h.keep_if {|k, c| c > 1}.keys
if res.size == 0
puts "All #{string.size} characters are used only once. This is unique"
else
puts "Not unique #{res.join(', ')} are used more than once"
end
end
is_unique?("This is a string") # Not unique i, s are used more than once
is_unique?("two") # All 3 characters are used only once. This is unique
To check if a string is unique or not, you can try out this:
string_input.downcase.gsub(/[^a-z]/, '').split("").sort.join('') == ('a' .. 'z').to_a.join('')
This will return true, if all the characters in your string are unique and if they include all the 26 characters.
def has_uniq_letters?(str)
letters = str.gsub(/[^A-Za-z]/, '').chars
letters == letters.uniq
end
If this doesn't have to be case sensitive,
def has_uniq_letters?(str)
letters = str.downcase.gsub(/[^a-z]/, '').chars
letters == letters.uniq
end
In your example, you mentioned you wanted additional information about your string (list of unique characters, etc), so this example may also be useful to you.
# s = "Cwm fjord veg balks nth pyx quiz."
s = "This is a test string."
totals = Hash.new(0)
s.downcase.each_char { |c| totals[c] += 1 if ('a'..'z').cover?(c) }
duplicates, uniques = totals.partition { |k, v| v > 1 }
duplicates, uniques = Hash[duplicates], Hash[uniques]
# duplicates = {"t"=>4, "i"=>3, "s"=>4}
# uniques = {"h"=>1, "a"=>1, "e"=>1, "r"=>1, "n"=>1, "g"=>1}

Ruby getting the longest word of a sentence

I'm trying to create method named longest_word that takes a sentence as an argument and The function will return the longest word of the sentence.
My code is:
def longest_word(str)
words = str.split(' ')
longest_str = []
return longest_str.max
end
The shortest way is to use Enumerable's max_by:
def longest(string)
string.split(" ").max_by(&:length)
end
Using regexp will allow you to take into consideration punctuation marks.
s = "lorem ipsum, loremmm ipsummm? loremm ipsumm...."
first longest word:
s.split(/[^\w]+/).max_by(&:length)
# => "loremmm"
# or using scan
s.scan(/\b\w+\b/).max_by(&:length)
# => "loremmm"
Also you may be interested in getting all longest words:
s.scan(/\b\w+\b/).group_by(&:length).sort.last.last
# => ["loremmm", "ipsummm"]
It depends on how you want to split the string. If you are happy with using a single space, than this works:
def longest(source)
arr = source.split(" ")
arr.sort! { |a, b| b.length <=> a.length }
arr[0]
end
Otherwise, use a regular expression to catch whitespace and puntuaction.
def longest_word(sentence)
longest_word = ""
words = sentence.split(" ")
words.each do |word|
longest_word = word unless word.length < longest_word.length
end
longest_word
end
That's a simple way to approach it. You could also strip the punctuation using a gsub method.
Funcional Style Version
str.split(' ').reduce { |r, w| w.length > r.length ? w : r }
Another solution using max
str.split(' ').max { |a, b| a.length <=> b.length }
sort_by! and reverse!
def longest_word(sentence)
longw = sentence.split(" ")
longw.sort_by!(&:length).reverse!
p longw[0]
end
longest_word("once upon a time long ago a very longword")
If you truly want to do it in the Ruby way it would be:
def longest(sentence)
sentence.split(' ').sort! { |a, b| b.length <=> a.length }[0]
end
This is to strip the word from the extra chars
sen.gsub(/[^0-9a-z ]/i, '').split(" ").max_by(&:length)
Find Longest word in a string
sentence = "Hi, my name is Mesut. There is longestword here!"
def longest_word(string)
long = ""
string.split(" ").each do |sent|
if sent.length >= long.length
long = sent
end
end
return long
end
p longest_word(sentence)

Resources